From 514fee370d3b2e96a79c7ddcb8abebd41b396e7f Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Mon, 16 Aug 2021 21:35:08 -0700 Subject: [PATCH 01/54] Enhance openflow driver performance --- CMakeLists.txt | 2 +- include/aca_net_config.h | 2 + include/aca_on_demand_engine.h | 3 +- include/aca_ovs_control.h | 3 +- include/aca_ovs_l2_programmer.h | 7 + include/libfluid-base/OFClient.hh | 41 + include/libfluid-base/OFConnection.hh | 220 ++ include/libfluid-base/OFServer.hh | 134 + include/libfluid-base/OFServerSettings.hh | 165 + include/libfluid-base/TLS.hh | 24 + include/libfluid-base/base/BaseOFClient.hh | 52 + .../libfluid-base/base/BaseOFConnection.hh | 214 ++ include/libfluid-base/base/BaseOFServer.hh | 91 + include/libfluid-base/base/EventLoop.hh | 72 + include/libfluid-base/base/config.h | 60 + include/libfluid-base/base/of.hh | 147 + include/libfluid-msg/of10/of10action.hh | 306 ++ include/libfluid-msg/of10/of10common.hh | 198 ++ include/libfluid-msg/of10/of10match.hh | 100 + include/libfluid-msg/of10/openflow-10.h | 889 +++++ include/libfluid-msg/of10msg.hh | 865 +++++ include/libfluid-msg/of13/of13action.hh | 404 +++ include/libfluid-msg/of13/of13common.hh | 769 +++++ include/libfluid-msg/of13/of13instruction.hh | 288 ++ include/libfluid-msg/of13/of13match.hh | 1218 +++++++ include/libfluid-msg/of13/of13meter.hh | 315 ++ include/libfluid-msg/of13/openflow-13.h | 1718 ++++++++++ include/libfluid-msg/of13msg.hh | 1581 +++++++++ include/libfluid-msg/ofcommon/action.hh | 123 + include/libfluid-msg/ofcommon/common.hh | 544 +++ include/libfluid-msg/ofcommon/msg.hh | 493 +++ .../libfluid-msg/ofcommon/openflow-common.hh | 161 + include/libfluid-msg/util/ethaddr.hh | 37 + include/libfluid-msg/util/ipaddr.hh | 45 + include/libfluid-msg/util/util.h | 170 + include/of_controller.h | 80 + include/of_message.h | 79 + include/ovs_control.h | 247 +- src/CMakeLists.txt | 55 +- src/aca_main.cpp | 37 + src/net_config/aca_net_config.cpp | 31 + src/ovs/aca_ovs_l2_programmer.cpp | 138 +- src/ovs/aca_vlan_manager.cpp | 4 + src/ovs/libfluid-base/OFClient.cc | 66 + src/ovs/libfluid-base/OFConnection.cc | 86 + src/ovs/libfluid-base/OFServer.cc | 270 ++ src/ovs/libfluid-base/OFServerSettings.cc | 108 + src/ovs/libfluid-base/TLS.cc | 99 + src/ovs/libfluid-base/base/BaseOFClient.cc | 306 ++ .../libfluid-base/base/BaseOFConnection.cc | 358 ++ src/ovs/libfluid-base/base/BaseOFServer.cc | 270 ++ src/ovs/libfluid-base/base/EventLoop.cc | 78 + src/ovs/libfluid-msg/of10/of10action.cc | 501 +++ src/ovs/libfluid-msg/of10/of10common.cc | 333 ++ src/ovs/libfluid-msg/of10/of10match.cc | 157 + src/ovs/libfluid-msg/of10msg.cc | 1506 +++++++++ src/ovs/libfluid-msg/of13/of13action.cc | 626 ++++ src/ovs/libfluid-msg/of13/of13common.cc | 1337 ++++++++ src/ovs/libfluid-msg/of13/of13instruction.cc | 416 +++ src/ovs/libfluid-msg/of13/of13match.cc | 2733 +++++++++++++++ src/ovs/libfluid-msg/of13/of13meter.cc | 492 +++ src/ovs/libfluid-msg/of13msg.cc | 2940 +++++++++++++++++ src/ovs/libfluid-msg/ofcommon/action.cc | 226 ++ src/ovs/libfluid-msg/ofcommon/common.cc | 436 +++ src/ovs/libfluid-msg/ofcommon/msg.cc | 479 +++ src/ovs/libfluid-msg/util/ethaddr.cc | 65 + src/ovs/libfluid-msg/util/ipaddr.cc | 130 + src/ovs/of_controller.cpp | 166 + src/ovs/of_message.cpp | 270 ++ src/ovs/ovs_control.cpp | 2131 ++++++------ 70 files changed, 27507 insertions(+), 1210 deletions(-) create mode 100644 include/libfluid-base/OFClient.hh create mode 100644 include/libfluid-base/OFConnection.hh create mode 100644 include/libfluid-base/OFServer.hh create mode 100644 include/libfluid-base/OFServerSettings.hh create mode 100644 include/libfluid-base/TLS.hh create mode 100644 include/libfluid-base/base/BaseOFClient.hh create mode 100644 include/libfluid-base/base/BaseOFConnection.hh create mode 100644 include/libfluid-base/base/BaseOFServer.hh create mode 100644 include/libfluid-base/base/EventLoop.hh create mode 100644 include/libfluid-base/base/config.h create mode 100644 include/libfluid-base/base/of.hh create mode 100644 include/libfluid-msg/of10/of10action.hh create mode 100644 include/libfluid-msg/of10/of10common.hh create mode 100644 include/libfluid-msg/of10/of10match.hh create mode 100644 include/libfluid-msg/of10/openflow-10.h create mode 100644 include/libfluid-msg/of10msg.hh create mode 100644 include/libfluid-msg/of13/of13action.hh create mode 100644 include/libfluid-msg/of13/of13common.hh create mode 100644 include/libfluid-msg/of13/of13instruction.hh create mode 100644 include/libfluid-msg/of13/of13match.hh create mode 100644 include/libfluid-msg/of13/of13meter.hh create mode 100644 include/libfluid-msg/of13/openflow-13.h create mode 100644 include/libfluid-msg/of13msg.hh create mode 100644 include/libfluid-msg/ofcommon/action.hh create mode 100644 include/libfluid-msg/ofcommon/common.hh create mode 100644 include/libfluid-msg/ofcommon/msg.hh create mode 100644 include/libfluid-msg/ofcommon/openflow-common.hh create mode 100644 include/libfluid-msg/util/ethaddr.hh create mode 100644 include/libfluid-msg/util/ipaddr.hh create mode 100644 include/libfluid-msg/util/util.h create mode 100644 include/of_controller.h create mode 100644 include/of_message.h create mode 100644 src/ovs/libfluid-base/OFClient.cc create mode 100644 src/ovs/libfluid-base/OFConnection.cc create mode 100644 src/ovs/libfluid-base/OFServer.cc create mode 100644 src/ovs/libfluid-base/OFServerSettings.cc create mode 100644 src/ovs/libfluid-base/TLS.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFClient.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFConnection.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFServer.cc create mode 100644 src/ovs/libfluid-base/base/EventLoop.cc create mode 100644 src/ovs/libfluid-msg/of10/of10action.cc create mode 100644 src/ovs/libfluid-msg/of10/of10common.cc create mode 100644 src/ovs/libfluid-msg/of10/of10match.cc create mode 100644 src/ovs/libfluid-msg/of10msg.cc create mode 100644 src/ovs/libfluid-msg/of13/of13action.cc create mode 100644 src/ovs/libfluid-msg/of13/of13common.cc create mode 100644 src/ovs/libfluid-msg/of13/of13instruction.cc create mode 100644 src/ovs/libfluid-msg/of13/of13match.cc create mode 100644 src/ovs/libfluid-msg/of13/of13meter.cc create mode 100644 src/ovs/libfluid-msg/of13msg.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/action.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/common.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/msg.cc create mode 100644 src/ovs/libfluid-msg/util/ethaddr.cc create mode 100644 src/ovs/libfluid-msg/util/ipaddr.cc create mode 100644 src/ovs/of_controller.cpp create mode 100644 src/ovs/of_message.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dc4e529..3f473d34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(CPPKAFKA_VERSION "${CPPKAFKA_VERSION_MAJOR}.${CPPKAFKA_VERSION_MINOR}.${CPPK set(RDKAFKA_MIN_VERSION 0x00090400) #add_compile_options(-O0) # enable no optimization during development -add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror) +add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Wno-error -Wno-unused-variable -Wno-unused-parameter -Wno-sequence-point -Wno-parentheses -Wno-pedantic -Wno-reorder -Wno-sign-compare) add_subdirectory(src) add_subdirectory(test) diff --git a/include/aca_net_config.h b/include/aca_net_config.h index cbc3333f..c0db0e08 100644 --- a/include/aca_net_config.h +++ b/include/aca_net_config.h @@ -56,6 +56,8 @@ class Aca_Net_Config { int execute_system_command(string cmd_string, ulong &culminative_time); + std::string execute_system_command_with_return(string cmd_string); + // compiler will flag error when below is called Aca_Net_Config(Aca_Net_Config const &) = delete; void operator=(Aca_Net_Config const &) = delete; diff --git a/include/aca_on_demand_engine.h b/include/aca_on_demand_engine.h index b2f21eeb..577610e3 100644 --- a/include/aca_on_demand_engine.h +++ b/include/aca_on_demand_engine.h @@ -21,7 +21,8 @@ #include "common.pb.h" #include -#include +//#include +#include #include #include #include "hashmap/HashMap.h" diff --git a/include/aca_ovs_control.h b/include/aca_ovs_control.h index e5a2137c..151fd66b 100644 --- a/include/aca_ovs_control.h +++ b/include/aca_ovs_control.h @@ -20,7 +20,8 @@ #define STDOUT_FILENO 1 /* Standard output. */ #include -#include +//#include +#include #include // OVS monitor implementation class diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index a1d000ff..41d556ba 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -17,6 +17,7 @@ #include "goalstateprovisioner.grpc.pb.h" #include +#include #define PRIORITY_HIGH 50 #define PRIORITY_MID 25 @@ -37,6 +38,12 @@ class ACA_OVS_L2_Programmer { int setup_ovs_bridges_if_need(); + int setup_ovs_default_flows(); + + int setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port); + + std::unordered_map get_ovs_bridge_mapping(); + int create_port(const std::string vpc_id, const std::string port_name, const std::string virtual_ip, const std::string virtual_mac, uint tunnel_id, ulong &culminative_time); diff --git a/include/libfluid-base/OFClient.hh b/include/libfluid-base/OFClient.hh new file mode 100644 index 00000000..2aaa89d0 --- /dev/null +++ b/include/libfluid-base/OFClient.hh @@ -0,0 +1,41 @@ +#pragma once + +#include "base/BaseOFConnection.hh" +#include "base/BaseOFClient.hh" +#include "OFServer.hh" +#include "OFConnection.hh" +#include "OFServerSettings.hh" +#include + +namespace fluid_base { + +class OFClient : private BaseOFClient, private OFConnectionProcessor, public OFHandler { +public: + OFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure, + const struct OFServerSettings ofsc = OFServerSettings()); + virtual ~OFClient(); + + virtual bool start(bool block = false); + + virtual void stop(); + + void set_config(OFServerSettings ofsc); + + // virtual void connection_callback(OFConnection *conn, OFConnection::Event event_type){}; + // virtual void message_callback(OFConnection *conn, uint8_t type, void *data, size_t len){}; + virtual void free_data(void* data) final; + +protected: + void base_message_callback(BaseOFConnection* c, void* data, size_t len) final; + void base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) final; + + void on_new_conn(OFConnection* cc) final; + + std::unique_ptr conn; +}; + +} // namespace fluid_base \ No newline at end of file diff --git a/include/libfluid-base/OFConnection.hh b/include/libfluid-base/OFConnection.hh new file mode 100644 index 00000000..49c32d4c --- /dev/null +++ b/include/libfluid-base/OFConnection.hh @@ -0,0 +1,220 @@ +/** @file */ +#ifndef __OFCONNECTION_HH__ +#define __OFCONNECTION_HH__ + +#include +#include + +namespace fluid_base { +class BaseOFConnection; +class OFHandler; + +/** +An OFConnection represents an OpenFlow connection with basic protocol +knowledge. It wraps a BaseOFConnection object, providing further abstractions +on top of it. +*/ +class OFConnection { +public: + /** + Create an OFConnection. + + @param c the BaseOFConnection object that this OFConnection will represent + @param ofhandler the OFHandler instance responsible for this OFConnection + */ + OFConnection(BaseOFConnection* c, OFHandler* ofhandler); + + /** Represents the state of an OFConnection. */ + enum State { + /** Sent hello message, waiting for reply */ + STATE_HANDSHAKE, + /** Version negotiation done, features request received */ + STATE_RUNNING, + /** Version negotiation failed, connection closed */ + STATE_FAILED, + /** OFConnection is down, unable to send/receive data (it will be closed + automatically). It represents a disconnection event at the controller + level. */ + STATE_DOWN + }; + + /** + OFConnection events. In the descriptions below, "safe to use" means that + messages can be sent and received normally according to the OpenFlow + specification. + */ + enum Event { + /** The connection has been started, but it is still waiting for the + OpenFlow handshake. It is not safe to use the connection. */ + EVENT_STARTED, + + /** The connection has been established (OpenFlow handshake complete). + It is safe to use the connection. */ + EVENT_ESTABLISHED, + + /** The version negotiation has failed because the parts cannot talk in + a common OpenFlow version. It is not safe to use the connection. */ + EVENT_FAILED_NEGOTIATION, + + /** The connection has been closed. It is not safe to use the + connection. */ + EVENT_CLOSED, + + /** The connection has been closed due to inactivity (no response to + echo requests). It is not safe to use the connection. */ + EVENT_DEAD, + }; + + /** Get the connection ID. */ + int get_id(); + + /** Get switch IP address. */ + std::string get_peer_address(); + + /** Check if the connection is alive (responding to echo requests). */ + bool is_alive(); + + /** Update the liveness state of the connection. */ + void set_alive(bool alive); + + /** + Get the connection state. See #OFConnection::State. + */ + uint8_t get_state(); + + /** + Set the connection state. See #OFConnection::State. + + @param state the new state. + */ + void set_state(OFConnection::State state); + + /** + Get the negotiated OpenFlow version for the connection (OpenFlow protocol + version number). Note that this is not an OFVersion value. It is the value + that goes into the OpenFlow header (e.g.: 4 for OpenFlow 1.3). */ + uint8_t get_version(); + + /** + Set a negotiated version for the connection. (OpenFlow protocol version + number). Note that this is not an OFVersion value. It is the value + that goes into the OpenFlow header (e.g.: 4 for OpenFlow 1.3). + + @param version an OpenFlow version number + */ + void set_version(uint8_t version); + + /** + Return the OFHandler instance responsible for the connection. + */ + OFHandler* get_ofhandler(); + + /** + Send data to through the connection. + + @param data the binary data to send + @param len length of the binary data (in bytes) + */ + void send(void* data, size_t len); + + /** + Set up a function to be called forever with an argument at a regular + interval. This is a utility function provided for no specific use case, but + rather because it is frequently needed. + + This method is thread-safe. + + @param cb the callback function. It should accept a void* argument and + return a void*. + @param interval interval in milisseconds + @param arg an argument to the callback function + */ + void add_timed_callback(void* (*cb)(void*), int interval, void* arg); + // TODO: add the option for the function to unschedule itself by returning + // false + + /** + Get application data. This data is any piece of data you might want to + associated with this OFConnection object. + */ + void* get_application_data(); + + /** + Set application data. + + See OFConnection::get_application_data. + + @param data a pointer to application data + */ + void set_application_data(void* data); + + /** + Close the connection. + This will not trigger OFServer::connection_callback. + */ + void close(); + +private: + BaseOFConnection* conn; + int id; + std::string peer_address; + State state; + uint8_t version; + bool alive; + OFHandler* ofhandler; + void* application_data; +}; + +/** +OFHandler is an abstract class. Its methods must be implemented by classes that +deal with OFConnection events (usually classes that manage one or more +OFConnection objects). +*/ +class OFHandler { +public: + virtual ~OFHandler() {} + + /** + Callback for connection events. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it will possibly be called + from several threads (on which connection events are being created). + + @param conn the OFConnection on which the message was received + @param event_type the event type (see #Event) + */ + virtual void connection_callback(OFConnection* conn, OFConnection::Event event_type) = 0; + + /** + Callback for new messages. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it will possibly be called + from several threads (on which message events are being created). + + By default, the message data will managed (freed) for you. If you want a + zero-copy behavior, see OFServerSettings::keep_data_ownership. + + @param conn the OFConnection on which the message was received + @param type OpenFlow message type + @param data binary message data + @param len message length + */ + virtual void message_callback(OFConnection* conn, uint8_t type, void* data, size_t len) = 0; + + /** + Free the data passed to OFHandler::message_callback. + */ + virtual void free_data(void* data) = 0; +}; + +} + +#endif diff --git a/include/libfluid-base/OFServer.hh b/include/libfluid-base/OFServer.hh new file mode 100644 index 00000000..c38c0f41 --- /dev/null +++ b/include/libfluid-base/OFServer.hh @@ -0,0 +1,134 @@ +/** @file */ +#ifndef __OFSERVER_HH__ +#define __OFSERVER_HH__ + +#include + +#include + +#include "base/BaseOFConnection.hh" +#include "base/BaseOFServer.hh" +#include "OFConnection.hh" +#include "OFServerSettings.hh" + +/** +Classes for creating an OpenFlow server that listens to connections and handles +events. +*/ +namespace fluid_base { +class OFConnectionProcessor { +public: + OFConnectionProcessor(OFHandler* h); + + void set_config(OFServerSettings ofsc); + void base_connection_callback(BaseOFConnection* conn, BaseOFConnection::Event event_type); + void base_message_callback(BaseOFConnection* conn, void* data, size_t len); + +private: + static void* send_echo(void* arg); + void free_data(void* data); + + virtual void on_new_conn(OFConnection* cc) = 0; + +private: + OFServerSettings ofsc; + OFHandler* _handler; +}; +/** +An OFServer manages OpenFlow connections and abstracts their events through +callbacks. It provides some of the basic functionalities: OpenFlow connection +setup and liveness check. + +Tipically a controller or low-level controller base class will inherit from +OFServer and implement the message_callback and connection_callback methods +to implement further functionality. +*/ +class OFServer : private BaseOFServer, private OFConnectionProcessor, public OFHandler { +public: + /** + Create an OFServer. + + @param address address to bind the server + @param port TCP port on which the server will listen + @param nthreads number of threads to run. Connections will be attributed to + event loops running on threads on a round-robin fashion. + The first event loop will also listen for new connections. + @param secure whether the connections should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init + before you can use this feature. + @param ofsc the optional server configuration parameters. If no value is + provided, default settings will be used. See OFServerSettings. + */ + OFServer(const char* address, + const int port, + const int nthreads = 4, + const bool secure = false, + const struct OFServerSettings ofsc = OFServerSettings()); + virtual ~OFServer(); + + /** + Start the server. It will listen at the port declared in the + constructor, handling connections in different threads and optionally + blocking the calling thread until OFServer::stop is called. + + @param block block the calling thread while the server is running + */ + // We reimplement this so that SWIG bindings don't have know BaseOFServer + virtual bool start(bool block = false); + + /** + Stop the server. It will close all connections, ask the theads handling + connections to finish. + + It will eventually unblock OFServer::start if it is blocking. + */ + virtual void stop(); + + /** + Retrieve an OFConnection object associated with this OFServer with a given + id. + + @param id OFConnection id + */ + OFConnection* get_ofconnection(int id); + + /** + Set configuration parameters for this OFServer. + + This method should be called before OFServer::start is called. Doing + otherwise will result in undefined settings behavior. In theory, it will + work fine, but unpredictable behavior can happen, and some settings will + only apply to new connections. + + You will usually initialize the settings in the constructor. This method + is provided to give more flexibility to implementations. + + @param ofsc an OFServerSettings object with the desired settings + */ + void set_config(OFServerSettings ofsc); + + virtual void connection_callback(OFConnection* conn, OFConnection::Event event_type) {}; + virtual void message_callback(OFConnection* conn, uint8_t type, void* data, size_t len) {}; + virtual void free_data(void* data) override; + +protected: + OFServerSettings ofsc; + std::map ofconnections; + pthread_mutex_t ofconnections_lock; + + inline void lock_ofconnections() { + pthread_mutex_lock(&ofconnections_lock); + } + + inline void unlock_ofconnections() { + pthread_mutex_unlock(&ofconnections_lock); + } + + void base_message_callback(BaseOFConnection* c, void* data, size_t len) final; + void base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) final; + + void on_new_conn(OFConnection* cc) final; +}; +} + +#endif diff --git a/include/libfluid-base/OFServerSettings.hh b/include/libfluid-base/OFServerSettings.hh new file mode 100644 index 00000000..f2158251 --- /dev/null +++ b/include/libfluid-base/OFServerSettings.hh @@ -0,0 +1,165 @@ +/** @file */ +#ifndef __OFSERVERSETTINGS_HH__ +#define __OFSERVERSETTINGS_HH__ + +#include + +namespace fluid_base { + +#define ECHO_XID 0x0F +#define HELLO_XID 0x0F + +class OFServer; + +/** +Configuration parameters for an OFServer. These parameters specify the +OpenFlow behavior of a class that deals with OFConnection objects. +*/ +class OFServerSettings { +public: + /** + Create an OFServerSettings with default configuration values. + + Settings will have the following values by default: + - Only OpenFlow 1.0 is supported (a sane value for the most compatibility) + - `echo_interval`: `15` + - `liveness_check`: `true` + - `handshake`: `true` + - `dispatch_all_messages`: `false` + - `use_hello_elems`: `false` (to avoid compatibility issues with + existing software and hardware) + - `keep_data_ownership`: `true` (to simplify things) + */ + OFServerSettings(); + + /** + Add a supported version to the set of supported versions. + + Using this method will override the default version (1, OpenFlow 1.0). If + you call this method with version 4, only version 4 will be supported. If + you want to add support for version 1, you will need to do so explicitly, + so that you can choose only the versions you want, while still having a + nice default. + + @param version OpenFlow protocol version number (e.g.: 4 for OpenFlow 1.3) + */ + OFServerSettings& supported_version(const uint8_t version); + + /** + Return an array of OpenFlow versions bitmaps with the supported versions. + */ + uint32_t* supported_versions(); + + /** + Return the largest version number supported. + */ + uint8_t max_supported_version(); + + /** + Set the OpenFlow echo interval (in seconds). A connection will be closed if + no echo replies arrive in this interval, and echo requests will be + periodically sent using the same interval. + + @param echo_interval the echo interval (in seconds) + */ + OFServerSettings& echo_interval(const int echo_interval); + + /** + Return the echo interval. + */ + int echo_interval(); + + /** + Set whether the OFServer instance should perform liveness checks (timed + echo requests and replies). + + @param liveness_check true for liveness checking + */ + OFServerSettings& liveness_check(const bool liveness_check); + + /** + Return whether liveness check should be performed. + */ + bool liveness_check(); + + /** + Set whether the OFServer instance should perform OpenFlow handshakes (hello + messages, version negotiation and features request). + + @param handshake true for automatic OpenFlow handshakes + */ + OFServerSettings& handshake(const bool handshake); + + /** + Return whether handshake should be performed. + */ + bool handshake(); + + /** + Set whether the OFServer instance should forward all OpenFlow messages to + the user callback (OFHandler::message_callback), including those treated + for handshake and liveness check. + + @param dispatch_all_messages true to enable forwarding for all messages + */ + OFServerSettings& dispatch_all_messages(const bool dispatch_all_messages); + + /** + Return whether all messages should be dispatched. + */ + bool dispatch_all_messages(); + + /** + Set whether the OFServer instance should send and treat OpenFlow 1.3.1 + hello elements. + + See OFServerSettings::OFServerSettings for more details. + + @param use_hello_elements true to enable hello elems + */ + OFServerSettings& use_hello_elements(const bool use_hello_elements); + + /** + Return whether hello elements should be used. + */ + bool use_hello_elements(); + + /** + Set whether the OFServer instance should own and manage the message data + passed to its message callback (true) or if your application should be + responsible for it (false). + + See OFServerSettings::OFServerSettings for more details. + + @param keep_data_ownership true if OFServer is responsible for managing + message data, false if your application is. + + */ + OFServerSettings& keep_data_ownership(const bool keep_data_ownership); + + /** + Return whether message data pointer ownership belongs to OFServer (true) or + your application (false). + */ + bool keep_data_ownership(); + + private: + friend class OFServer; + + uint32_t _supported_versions; + uint8_t _max_supported_version; + + bool version_set_by_hand; + void add_version(const uint8_t version); + + int _echo_interval; + bool _liveness_check; + bool _handshake; + bool _dispatch_all_messages; + bool _use_hello_elements; + bool _keep_data_ownership; +}; + +} + +#endif diff --git a/include/libfluid-base/TLS.hh b/include/libfluid-base/TLS.hh new file mode 100644 index 00000000..a09dab99 --- /dev/null +++ b/include/libfluid-base/TLS.hh @@ -0,0 +1,24 @@ +/** @file Functions for secure communication using SSL */ +#ifndef __SSL_IMPL_HH__ +#define __SSL_IMPL_HH__ + +namespace fluid_base { + /** SSL implementation pointer for internal library use. */ + extern void* tls_obj; + + /** Initialize SSL parameters. You must call this function before + asking any object to communicate in a secure manner. + + @param cert The controller's certificate signed by a CA + @param privkey The controller's private key to be used with the + certificate + @param trustedcert A CA certificate that signs certificates of trusted + switches */ + void libfluid_tls_init(const char* cert, const char* privkey, const char* trustedcert); + + /** Free SSL data. You must call this function after you don't need secure + communication anymore. */ + void libfluid_tls_clear(); +} + +#endif \ No newline at end of file diff --git a/include/libfluid-base/base/BaseOFClient.hh b/include/libfluid-base/base/BaseOFClient.hh new file mode 100644 index 00000000..21356b01 --- /dev/null +++ b/include/libfluid-base/base/BaseOFClient.hh @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include "EventLoop.hh" +#include "BaseOFConnection.hh" + +#include + +namespace fluid_base { + +class BaseOFClient : public BaseOFHandler { +public: + BaseOFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure); + virtual ~BaseOFClient(); + + bool start(bool block = false); + void stop(); + + // BaseOFHandler methods + // virtual void base_connection_callback( + // BaseOFConnection* conn, + // BaseOFConnection::Event event_type) override; + // virtual void base_message_callback(BaseOFConnection* conn, void* data, size_t len); + virtual void free_data(void* data) override; + +protected: + bool connect(); + +private: + const std::string address; + const bool domainsocket; + const int port; + const bool secure; + + bool blocking; + + EventLoop* evloop; + pthread_t evthread; + int nconn; + + class LibEventBaseOFClient; + friend class LibEventBaseOFClient; + LibEventBaseOFClient* m_implementation; +}; + +} // namespace fluid_base \ No newline at end of file diff --git a/include/libfluid-base/base/BaseOFConnection.hh b/include/libfluid-base/base/BaseOFConnection.hh new file mode 100644 index 00000000..62e8130b --- /dev/null +++ b/include/libfluid-base/base/BaseOFConnection.hh @@ -0,0 +1,214 @@ +/** @file */ +#ifndef __BASEOFCONNECTION_HH__ +#define __BASEOFCONNECTION_HH__ + +#include +#include +#include + +#include "EventLoop.hh" + +namespace fluid_base { +class BaseOFHandler; + +/** +A BaseOFConnection wraps the basic functionalities of a network connection with +OpenFlow-oriented messaging features. It uses an OFReadBuffer for building the +messages being read and dispatches events to a BaseOFHandler (who created it). + +This connection will tipically be wrapped by a higher-level connection object +(a manager object) providing further protocol semantics on top of it. +*/ +class BaseOFConnection { +public: + /** + Create a BaseOFConnection. + + @param id connection id + @param ofhandler the BaseOFHandler for this connection + @param evloop the EventLoop that will run this connection + @param fd the OS-level file descriptor for this connection + + @param secure whether the connection should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init before you + can use this feature. + */ + BaseOFConnection(int id, + BaseOFHandler* ofhandler, + EventLoop* evloop, + int fd, + bool secure, + std::string peer_address); + virtual ~BaseOFConnection(); + + /** BaseOFConnection events. */ + enum Event { + /** The connection has been successfully established */ + EVENT_UP, + /** The other end has ended the connection */ + EVENT_DOWN, + /** The connection resources have been released and freed */ + EVENT_CLOSED + }; + + /** + Send a message through this connection. + + This method is thread-safe. + + @param data binary message data + @param len message length in bytes + */ + void send(void* data, size_t len); + + /** + Set up a function to be called forever with an argument at a regular + interval. + + This method is thread-safe. + + @param cb the callback function. It should accept a void* argument and + return a void*. + @param interval interval in milisseconds + @param arg an argument to the callback function + */ + void add_timed_callback(void* (*cb)(void*), int interval, void* arg); + // TODO: add the option for the function to unschedule itself by returning + // false + + // TODO: these methods are not thread-safe, and they really aren't + // currently called from more than one thread. But perhaps we should + // consider that... + + /** + Set the manager for this connection. A manager provides further protocol + semantics on top of a BaseOFConnection. This manager will tipically be used + by an upper-level abstraction on top of BaseOFHandler to create its own + representation of an OpenFlow connection that uses this connection. + + This method is not thread-safe. + + @param manager the manager object + */ + void set_manager(void* manager); + + /** + Get the manager for this connection. See BaseOFConnection::set_manager. + + This method is not thread-safe. + */ + void* get_manager(); + + /** + Get the connection id. + */ + int get_id(); + + /** + Get switch IP address. + */ + std::string get_peer_address(); + + /** + Close this connection. It won't be closed immediately (remaining connection + and message callbacks may still be called). + + After it is closed, the resources associated with this connection will be + freed, and no more callbacks will be invoked. Performing any further + operations on this connection will lead to undefined behavior. + + This method is thread-safe. + */ + void close(); + + /** + Free the dynamically allocated data sent to the message callback. + + @param data dynamically allocated data sent to the message callback + */ + static void free_data(void* data); + +private: + int id; + EventLoop* evloop; + class OFReadBuffer; + OFReadBuffer* buffer; + void* manager; + bool secure; + BaseOFHandler* ofhandler; + std::string peer_address; + + bool running; + + // Types for internal use (timed callbacks) + struct timed_callback { + void* (*cb)(void*); + void* cb_arg; + void* data; + }; + std::vector timed_callbacks; + + void notify_msg_cb(void* data, size_t n); + void notify_conn_cb(BaseOFConnection::Event event_type); + void do_close(); + + class LibEventBaseOFConnection; + friend class LibEventBaseOFConnection; + LibEventBaseOFConnection* m_implementation; +}; + +/** +BaseOFHandler is an abstract class. Its methods must be implemented by classes +that deal with BaseOFConnection events (usually classes that manage one or more +BaseOFConnection objects). */ +class BaseOFHandler { +public: + virtual ~BaseOFHandler() {} + + /** + Callback for connection events. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it may be called by several + EventLoop instances, each running in a thread. + + @param conn the BaseOFConnection on which the message was received + @param event_type the event type (see #BaseOFConnectionEvent) + */ + virtual void base_connection_callback(BaseOFConnection* conn, + BaseOFConnection::Event event_type) + = 0; + + /** + Callback for new messages. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it may be called by several + EventLoop instances, each running in a thread. + + The message data will not be freed. To free it, you should call + BaseOFConnection::free_data when you are done with it. + + @param conn the BaseOFConnection on which the message was received + @param data binary message data + @param len message length + */ + virtual void base_message_callback(BaseOFConnection* conn, + void* data, + size_t len) = 0; + + /** + Free the data passed to BaseOFHandler::base_message_callback. + */ + virtual void free_data(void* data) = 0; +}; + +} + +#endif diff --git a/include/libfluid-base/base/BaseOFServer.hh b/include/libfluid-base/base/BaseOFServer.hh new file mode 100644 index 00000000..2eece696 --- /dev/null +++ b/include/libfluid-base/base/BaseOFServer.hh @@ -0,0 +1,91 @@ +/** @file */ +#ifndef __BASEOFSERVER_HH__ +#define __BASEOFSERVER_HH__ + +#include +#include + +#include "EventLoop.hh" +#include "BaseOFConnection.hh" + +#include + +namespace fluid_base { + +/** +A BaseOFServer manages the very basic functions of OpenFlow connections, such +as notifying of new messages and network-level events. It is an abstract class +that should be overriden by another class to provide OpenFlow features. +*/ +class BaseOFServer : public BaseOFHandler { +public: + /** + Create a BaseOFServer. + + @param address address to bind the server + @param port TCP port on which the server will listen + @param nevloops number of event loops to run. Connections will be + attributed to event loops running on threads on a + round-robin fashion. The first event loop will listen for + new connections. + @param secure whether the connections should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init before you + can use this feature. + */ + BaseOFServer(const char* address, + const int port, + const int nevloops = 1, + const bool secure = false); + virtual ~BaseOFServer(); + + /** + Start the server. It will listen at the port declared in the + constructor, assigning connections to event loops running in threads and + optionally blocking the calling thread until BaseOFServer::stop is called. + + @param block block the calling thread while the server is running + */ + virtual bool start(bool block = false); + + /** + Stop the server. It will stop listening to new connections and signal the + event loops to stop running. + + It will eventually unblock BaseOFServer::start if it is blocking. + */ + virtual void stop(); + + // BaseOFHandler methods + virtual void base_connection_callback(BaseOFConnection* conn, + BaseOFConnection::Event event_type); + virtual void base_message_callback(BaseOFConnection* conn, + void* data, + size_t len) { printf("Calling fake msgcb\n"); }; + virtual void free_data(void* data); + +private: + // TODO: hide part of this in LibEventBaseOFServer + char* address; + char port[6]; + + EventLoop** eventloops; + EventLoop* main; + pthread_t* threads; + bool blocking; + bool secure; + + int eventloop; + int nthreads; + int nconn; + + bool listen(EventLoop* w); + EventLoop* choose_eventloop(); + + class LibEventBaseOFServer; + friend class LibEventBaseOFServer; + LibEventBaseOFServer* m_implementation; +}; + +} + +#endif diff --git a/include/libfluid-base/base/EventLoop.hh b/include/libfluid-base/base/EventLoop.hh new file mode 100644 index 00000000..d6f53177 --- /dev/null +++ b/include/libfluid-base/base/EventLoop.hh @@ -0,0 +1,72 @@ +/** @file */ +#ifndef __EVENTLOOP_HH__ +#define __EVENTLOOP_HH__ + +namespace fluid_base { + +class BaseOFServer; +class BaseOFConnection; +class OvsdbClient; +class OvsdbConnection; +class BaseOFClient; + +/** +A EventLoop runs an event loop for connections. It will activate the callbacks +associated with them. The class using an EventLoop should tipically assign +incoming connections in a round-robin fashion. + +There might be more than one event loop in use in applications. In this case, +each EventLoop can be run in a thread. +*/ +// An EventLoop is pretty much a simple wrapper around libevent's event_base +class EventLoop { +public: + /** + Create a EventLoop. + + @param id event loop id + */ + EventLoop(int id); + ~EventLoop(); + + /** + Run this event loop (which will block the calling thread). When + EventLoop::stop is called, this method will unblock, run the callbacks + of pending events and return. + + Calling EventLoop::stop first will prevent this method from running. */ + void run(); + + /** + Force the event loop to stop. It will finish running the current event + callback and then force EventLoop::run to continue its flow (deal with + remaining events and quit). + + Calling this method first will prevent EventLoop::run from running. */ + void stop(); + + /** + This method is just an adapter for passing the EventLoop::run method to + pthread_create. */ + static void* thread_adapter(void* arg); + + +private: + int id; + bool stopped; + + friend class BaseOFServer; + friend class BaseOFConnection; + friend class OvsdbClient; + friend class OvsdbConnection; + friend class BaseOFClient; + void* get_base(); + + class LibEventEventLoop; + friend class LibEventEventLoop; + LibEventEventLoop* m_implementation; +}; + +} + +#endif \ No newline at end of file diff --git a/include/libfluid-base/base/config.h b/include/libfluid-base/base/config.h new file mode 100644 index 00000000..9cbddd07 --- /dev/null +++ b/include/libfluid-base/base/config.h @@ -0,0 +1,60 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if the system has OpenSSL TLS support */ +// for arm, this not work +// #define HAVE_TLS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "allanv@cpqd.com.br" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libfluid_base" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libfluid_base 1.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libfluid_base" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.cpqd.com.br/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 diff --git a/include/libfluid-base/base/of.hh b/include/libfluid-base/base/of.hh new file mode 100644 index 00000000..e3ea1216 --- /dev/null +++ b/include/libfluid-base/base/of.hh @@ -0,0 +1,147 @@ +/* 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. + */ + +/* OpenFlow: protocol between controller and datapath. + +This is a simplified version of the OpenFlow header that should be valid for +all OpenFlow versions. +*/ + +#ifndef OPENFLOW_OPENFLOW_H +#define OPENFLOW_OPENFLOW_H 1 + +#ifdef __KERNEL__ +#include +#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; })] +#else /* __cplusplus */ +#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] +#endif /* __cplusplus */ + +#ifndef SWIG +#define OFP_PACKED __attribute__((packed)) +#else +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ +}; + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_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_fluid_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 this element. */ +}; +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. */ + /* 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_fluid_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); + +/* 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, /* Hello protocol failed. */ +}; + +/* ofp_fluid_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, /* No compatible version. */ +}; + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_fluid_error_msg { + struct ofp_fluid_header header; + + uint16_t type; + uint16_t code; + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_error_msg) == 12); + +#endif diff --git a/include/libfluid-msg/of10/of10action.hh b/include/libfluid-msg/of10/of10action.hh new file mode 100644 index 00000000..f6a3270b --- /dev/null +++ b/include/libfluid-msg/of10/of10action.hh @@ -0,0 +1,306 @@ +#ifndef OF10ACTION_H +#define OF10ACTION_H + +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "../ofcommon/action.hh" + +namespace fluid_msg { + +namespace of10 { + +class OutputAction: public Action { +private: + uint16_t port_; + uint16_t max_len_; +public: + OutputAction(); + OutputAction(uint16_t port, uint16_t max_len); + ~OutputAction() { + } + OutputAction* clone() { + return new OutputAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } + uint16_t max_len() { + return this->max_len_; + } + void max_len(uint16_t max_len) { + this->max_len_ = max_len; + } +}; + +class SetVLANVIDAction: public Action { +private: + uint16_t vlan_vid_; +public: + SetVLANVIDAction(); + SetVLANVIDAction(uint16_t vlan_vid); + ~SetVLANVIDAction() { + } + virtual SetVLANVIDAction* clone() { + return new SetVLANVIDAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t vlan_vid() { + return this->vlan_vid_; + } + void vlan_vid(uint16_t vlan_vid) { + this->vlan_vid_ = vlan_vid; + } +}; + +class SetVLANPCPAction: public Action { +private: + uint8_t vlan_pcp_; +public: + SetVLANPCPAction(); + SetVLANPCPAction(uint8_t vlan_pcp); + ~SetVLANPCPAction() { + } + virtual SetVLANPCPAction* clone() { + return new SetVLANPCPAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t vlan_pcp() { + return this->vlan_pcp_; + } + void vlan_pcp(uint8_t vlan_pcp) { + this->vlan_pcp_ = vlan_pcp; + } +}; + +class StripVLANAction: public Action { +public: + StripVLANAction(); + ~StripVLANAction() { + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual StripVLANAction* clone() { + return new StripVLANAction(*this); + } +}; + +class SetDLSrcAction: public Action { +private: + EthAddress dl_addr_; +public: + SetDLSrcAction(); + SetDLSrcAction(EthAddress dl_addr); + ~SetDLSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetDLSrcAction* clone() { + return new SetDLSrcAction(*this); + } + EthAddress dl_addr() { + return this->dl_addr_; + } + void dl_addr(const EthAddress &dl_addr) { + this->dl_addr_ = dl_addr; + } +}; + +class SetDLDstAction: public Action { +private: + EthAddress dl_addr_; +public: + SetDLDstAction(); + SetDLDstAction(EthAddress dl_addr); + ~SetDLDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetDLDstAction* clone() { + return new SetDLDstAction(*this); + } + EthAddress dl_addr() { + return this->dl_addr_; + } + void dl_addr(const EthAddress &dl_addr) { + this->dl_addr_ = dl_addr; + } + +}; + +class SetNWSrcAction: public Action { +private: + IPAddress nw_addr_; +public: + SetNWSrcAction(); + SetNWSrcAction(IPAddress nw_addr); + ~SetNWSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWSrcAction* clone() { + return new SetNWSrcAction(*this); + } + IPAddress nw_addr() { + return this->nw_addr_; + } + void nw_addr(const IPAddress &nw_addr) { + this->nw_addr_ = nw_addr; + } +}; + +class SetNWDstAction: public Action { +private: + IPAddress nw_addr_; +public: + SetNWDstAction(); + SetNWDstAction(IPAddress nw_addr); + ~SetNWDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWDstAction* clone() { + return new SetNWDstAction(*this); + } + IPAddress nw_addr() { + return this->nw_addr_; + } + void nw_addr(const IPAddress &nw_addr) { + this->nw_addr_ = nw_addr; + } +}; + +class SetNWTOSAction: public Action { +private: + uint8_t nw_tos_; +public: + SetNWTOSAction(); + SetNWTOSAction(uint8_t nw_tos); + ~SetNWTOSAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWTOSAction* clone() { + return new SetNWTOSAction(*this); + } + uint8_t nw_tos() { + return this->nw_tos_; + } + void nw_tos(uint8_t nw_tos) { + this->nw_tos_ = nw_tos; + } +}; + +class SetTPSrcAction: public Action { +private: + uint16_t tp_port_; +public: + SetTPSrcAction(); + SetTPSrcAction(uint16_t tp_port); + ~SetTPSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetTPSrcAction* clone() { + return new SetTPSrcAction(*this); + } + IPAddress tp_port() { + return this->tp_port_; + } + void tp_port(uint16_t tp_port) { + this->tp_port_ = tp_port; + } +}; + +class SetTPDstAction: public Action { +private: + uint16_t tp_port_; +public: + SetTPDstAction(); + SetTPDstAction(uint16_t tp_port); + ~SetTPDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetTPDstAction* clone() { + return new SetTPDstAction(*this); + } + IPAddress tp_port() { + return this->tp_port_; + } + void tp_port(uint16_t tp_port) { + this->tp_port_ = tp_port; + } +}; + +class EnqueueAction: public Action { +private: + uint16_t port_; + uint32_t queue_id_; +public: + EnqueueAction(); + EnqueueAction(uint16_t port, uint32_t queue_id); + ~EnqueueAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual EnqueueAction* clone() { + return new EnqueueAction(*this); + } + uint16_t port() { + return this->port_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port(uint16_t port) { + this->port_ = port; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +class VendorAction: public Action { +private: + uint32_t vendor_; +public: + VendorAction(); + VendorAction(uint32_t vendor); + ~VendorAction() { + } + virtual bool equals(const Action & other); + virtual VendorAction* clone() { + return new VendorAction(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +} //End of namespace of10 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of10/of10common.hh b/include/libfluid-msg/of10/of10common.hh new file mode 100644 index 00000000..1bfb6cd5 --- /dev/null +++ b/include/libfluid-msg/of10/of10common.hh @@ -0,0 +1,198 @@ +#ifndef OF10OPENFLOW_COMMON_H +#define OF10OPENFLOW_COMMON_H 1 + +#include +#include +#include "../util/util.h" +#include "../ofcommon/common.hh" +#include "openflow-10.h" +#include "of10action.hh" +#include "of10match.hh" + + +namespace fluid_msg { + +namespace of10 { + +class Port: public PortCommon { +private: + uint16_t port_no_; +public: + Port() { + } + Port(uint16_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer); + ~Port() { + } + bool operator==(const Port &other) const; + bool operator!=(const Port &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } + uint16_t port_no() { + return this->port_no_; + } + std::string name() { + return this->name_; + } +}; + +class QueuePropMinRate: public QueuePropRate { +public: + QueuePropMinRate() + : QueuePropRate(of10::OFPQT_MIN_RATE) { + } + QueuePropMinRate(uint16_t rate); + ~QueuePropMinRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMinRate* clone() { + return new QueuePropMinRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +/* Queue description*/ +class PacketQueue: public PacketQueueCommon { +public: + PacketQueue() { + } + PacketQueue(uint32_t queue_id); + PacketQueue(uint32_t queue_id, QueuePropertyList properties); + ~PacketQueue() { + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class FlowStats: public FlowStatsCommon { +private: + of10::Match match_; + ActionList actions_; +public: + FlowStats() { + } + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t cookie, uint64_t packet_count, uint64_t byte_count); + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t cookie, uint64_t packet_count, uint64_t byte_count, + of10::Match match, ActionList actions); + ~FlowStats() { + } + + bool operator==(const FlowStats &other) const; + bool operator!=(const FlowStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + of10::Match match() { + return this->match_; + } + ActionList actions() { + return this->actions_; + } + + void match(of10::Match match) { + this->match_ = match; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class TableStats: public TableStatsCommon { +private: + std::string name_; + uint32_t wildcards_; + uint32_t max_entries_; +public: + TableStats() { + } + + TableStats(uint8_t table_id, std::string name, uint32_t wildcards, + uint32_t max_entries, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count); + ~TableStats() { + } + + bool operator==(const TableStats &other) const; + bool operator!=(const TableStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::string name() { + return this->name_; + } + uint32_t wildcards() { + return this->wildcards_; + } + uint32_t max_entries() { + return this->max_entries_; + } + void name(std::string name) { + this->name_ = name; + } + void wildcards(uint32_t wildcards) { + this->wildcards_ = wildcards; + } + void max_entries(uint32_t max_entries) { + this->max_entries_ = max_entries; + } +}; + +class PortStats: public PortStatsCommon { +private: + uint16_t port_no_; +public: + PortStats() { + } + + PortStats(uint16_t port_no, struct port_rx_tx_stats tx_stats, + struct port_err_stats err_stats, uint64_t collisions); + ~PortStats() { + } + + bool operator==(const PortStats &other) const; + bool operator!=(const PortStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +class QueueStats: public QueueStatsCommon { +private: + uint16_t port_no_; +public: + QueueStats() { + } + + QueueStats(uint16_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors); + ~QueueStats() { + } + + bool operator==(const QueueStats &other) const; + bool operator!=(const QueueStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +} //End of namespace of10 +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/of10/of10match.hh b/include/libfluid-msg/of10/of10match.hh new file mode 100644 index 00000000..24f638d2 --- /dev/null +++ b/include/libfluid-msg/of10/of10match.hh @@ -0,0 +1,100 @@ +#ifndef OF10OPENFLOW_MATCH_H +#define OF10OPENFLOW_MATCH_H 1 + +#include +#include +#include "../util/util.h" +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "openflow-10.h" + +namespace fluid_msg { + +namespace of10 { + +class Match { +private: + uint32_t wildcards_; /* Wildcard fields. */ + uint16_t in_port_; /* Input switch port. */ + EthAddress dl_src_; /* Ethernet source address. */ + EthAddress dl_dst_; /* Ethernet destination address. */ + uint16_t dl_vlan_; /* Input VLAN id. */ + uint8_t dl_vlan_pcp_; /* Input VLAN priority. */ + uint16_t dl_type_; /* Ethernet frame type. */ + uint8_t nw_tos_; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto_; /* IP protocol or lower 8 bits of + * ARP opcode. */ + IPAddress nw_src_; /* IP source address. */ + IPAddress nw_dst_; /* IP destination address. */ + uint16_t tp_src_; /* TCP/UDP source port. */ + uint16_t tp_dst_; /* TCP/UDP destination port. */ +public: + Match(); + ~Match() { + } + ; + bool operator==(const Match &other) const; + bool operator!=(const Match &other) const; + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t wildcards() { + return this->wildcards_; + } + uint16_t in_port() { + return this->in_port_; + } + EthAddress dl_src() { + return this->dl_src_; + } + EthAddress dl_dst() { + return this->dl_dst_; + } + uint16_t dl_vlan() { + return this->dl_vlan_; + } + uint8_t dl_vlan_pcp() { + return this->dl_vlan_pcp_; + } + uint16_t dl_type() { + return this->dl_type_; + } + uint8_t nw_tos() { + return this->nw_tos_; + } + uint8_t nw_proto() { + return this->nw_proto_; + } + IPAddress nw_src() { + return this->nw_src_; + } + IPAddress nw_dst() { + return this->nw_dst_; + } + uint16_t tp_src() { + return this->tp_src_; + } + uint16_t tp_dst() { + return this->tp_dst_; + } + + void wildcards(uint32_t wildcards); + void in_port(uint16_t in_port); + void dl_src(const EthAddress &dl_src); + void dl_dst(const EthAddress &dl_dst); + void dl_vlan(uint16_t dl_vlan); + void dl_vlan_pcp(uint8_t dl_vlan_pcp); + void dl_type(uint16_t dl_type); + void nw_tos(uint8_t nw_tos); + void nw_proto(uint8_t nw_proto); + void nw_src(const IPAddress &nw_src); + void nw_dst(const IPAddress &nw_dst); + void nw_src(const IPAddress &nw_src, uint32_t prefix); + void nw_dst(const IPAddress &nw_src, uint32_t prefix); + void tp_src(uint16_t tp_src); + void tp_dst(uint16_t tp_dst); +}; + +} //End of Namespace of10 +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/of10/openflow-10.h b/include/libfluid-msg/of10/openflow-10.h new file mode 100644 index 00000000..dc1ceb39 --- /dev/null +++ b/include/libfluid-msg/of10/openflow-10.h @@ -0,0 +1,889 @@ +/* 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. + */ + +/* OpenFlow: protocol between controller and datapath. */ + +#ifndef OF10OPENFLOW_OPENFLOW_H +#define OF10OPENFLOW_OPENFLOW_H 1 + +#include "../ofcommon/openflow-common.hh" + +namespace fluid_msg { + +namespace of10 { + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +const uint8_t OFP_VERSION = 0x01; + +/* Port numbering. Physical ports are numbered starting from 1. */ +enum ofp_port { + /* Maximum number of physical switch ports. */ + OFPP_FLUID_MAX = 0xff00, + + /* Fake output "ports". */ + OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This + virtual port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfff9, /* Perform actions in flow table. + NB: This can only be the destination + port for packet-out messages. */ + OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ + OFPP_FLUID_FLOOD = 0xfffb, /* All physical ports except input port and + those disabled by STP. */ + OFPP_ALL = 0xfffc, /* All physical ports except input port. */ + OFPP_FLUID_CONTROLLER = 0xfffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ + OFPP_NONE = 0xffff /* Not associated with a physical port. */ +}; + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ + OFPT_SET_CONFIG, /* Controller/switch message */ + + /* Asynchronous messages. */ + OFPT_PACKET_IN, /* Async message */ + OFPT_FLOW_REMOVED, /* Async message */ + OFPT_PORT_STATUS, /* Async message */ + + /* Controller command messages. */ + OFPT_PACKET_OUT, /* Controller/switch message */ + OFPT_FLOW_MOD, /* Controller/switch message */ + OFPT_PORT_MOD, /* Controller/switch message */ + + /* Statistics messages. */ + OFPT_STATS_REQUEST, /* Controller/switch message */ + OFPT_STATS_REPLY, /* Controller/switch message */ + + /* Barrier messages. */ + OFPT_BARRIER_REQUEST, /* Controller/switch message */ + OFPT_BARRIER_REPLY, /* Controller/switch message */ + + /* Queue Configuration messages. */ + OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ + +}; + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_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_fluid_header) == 8); + +/* OFPT_HELLO. This message has an empty body, but implementations must + * ignore any data included in the body, to allow for future extensions. */ +struct ofp_hello { + struct ofp_fluid_header header; +}; + +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1, /* Drop fragments. */ + OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3 +}; + +/* 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_STP = 1 << 3, /* 802.1d spanning tree. */ + OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_phy_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_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ + OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning + tree packets. */ + OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ + OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ + 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. */ + + /* The OFPPS_STP_* bits have no effect on switch operation. The + * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and + * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning + * tree. */ + OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ + OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ + OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ + OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ + OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ +}; + +/* Features of physical 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_COPPER = 1 << 7, /* Copper medium. */ + OFPPF_FIBER = 1 << 8, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 10, /* Pause. */ + OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ +}; + +/* Description of a physical port */ +struct ofp_phy_port { + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; + 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_fluid_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 pad[3]; /* Align to 64-bits. */ + + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ + + /* Port info.*/ + struct ofp_phy_port ports[0]; /* Port definitions. The number of ports + is inferred from the length field in + the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); + +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD, /* The port was added. */ + OFPPR_DELETE, /* The port was removed. */ + OFPPR_MODIFY /* Some attribute of the port has changed. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_fluid_header header; + uint8_t reason; /* One of OFPPR_*. */ + uint8_t pad[7]; /* Align to 64-bits. */ + struct ofp_phy_port desc; +}; +OFP_ASSERT(sizeof(struct ofp_port_status) == 64); + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_fluid_header header; + uint16_t port_no; + 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_phy_port struct. */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all + bits to prevent any action taking place. */ + uint8_t pad[4]; /* Pad to 64-bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); + +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH, /* No matching flow. */ + OFPR_ACTION /* Action explicitly output to controller. */ +}; + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_fluid_header header; + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint16_t in_port; /* Port on which frame was received. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t pad; + uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, + so the IP header is 32-bit aligned. The + amount of data is inferred from the length + field in the header. Because of padding, + offsetof(struct ofp_packet_in, data) == + sizeof(struct ofp_packet_in) - 2. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); + +enum ofp_action_type { + OFPAT_OUTPUT, /* Output to switch port. */ + OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ + OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ + OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ + OFPAT_SET_DL_SRC, /* Ethernet source address. */ + OFPAT_SET_DL_DST, /* Ethernet destination address. */ + OFPAT_SET_NW_SRC, /* IP source address. */ + OFPAT_SET_NW_DST, /* IP destination address. */ + OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ + OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ + OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ + OFPAT_ENQUEUE, /* Output to queue. */ + OFPAT_VENDOR = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. + * When the 'port' is the OFPP_FLUID_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.*/ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 8. */ + uint16_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_output) == 8); + +/* Action structure for OFPAT_SET_VLAN_VID. */ +struct ofp_action_vlan_vid { + uint16_t type; /* OFPAT_SET_VLAN_VID. */ + uint16_t len; /* Length is 8. */ + uint16_t vlan_vid; /* VLAN id. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); + +/* Action structure for OFPAT_SET_VLAN_PCP. */ +struct ofp_action_vlan_pcp { + uint16_t type; /* OFPAT_SET_VLAN_PCP. */ + uint16_t len; /* Length is 8. */ + uint8_t vlan_pcp; /* VLAN priority. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); + +/* Action structure for OFPAT_SET_DL_SRC/DST. */ +struct ofp_action_dl_addr { + uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ + uint16_t len; /* Length is 16. */ + uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); + +/* Action structure for OFPAT_SET_NW_SRC/DST. */ +struct ofp_action_nw_addr { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint32_t nw_addr; /* IP address. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); + +/* Action structure for OFPAT_SET_TP_SRC/DST. */ +struct ofp_action_tp_port { + uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint16_t tp_port; /* TCP/UDP port. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); + +/* Action structure for OFPAT_SET_NW_TOS. */ +struct ofp_action_nw_tos { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); + +/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ +struct ofp_action_enqueue { + uint16_t type; /* OFPAT_ENQUEUE. */ + uint16_t len; /* Len is 16. */ + uint16_t port; /* Port that queue belongs. Should + refer to a valid physical port + (i.e. < OFPP_FLUID_MAX) or OFPP_IN_PORT. */ + uint8_t pad[6]; /* Pad for 64-bit alignment. */ + uint32_t queue_id; /* Where to enqueue the packets. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); + +/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ +struct ofp_action_vendor_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t vendor; /* Vendor ID, which takes the same form + as in "struct ofp_vendor_header". */ +}; +OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); + +/* 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); + +const uint32_t OFP_NO_BUFFER = 0xffffffff; + +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_fluid_header header; + uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ + uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ + uint16_t actions_len; /* Size of action array in bytes. */ + struct ofp_action_header actions[0]; /* Actions. */ + /* uint8_t data[0]; *//* Packet data. The length is inferred + from the length field in the header. + (Only meaningful if buffer_id == -1.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); + +enum ofp_flow_mod_command { + OFPFC_ADD, /* New flow. */ + OFPFC_MODIFY, /* Modify all matching flows. */ + OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ + OFPFC_DELETE, /* Delete all matching flows. */ + OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ +}; + +/* Flow wildcards. */ +enum ofp_flow_wildcards { + OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ + OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ + OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ + OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ + OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ + OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ + OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ + OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ + + /* IP source address wildcard bit count. 0 is exact match, 1 ignores the + * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard + * the entire field. This is the *opposite* of the usual convention where + * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ + OFPFW_NW_SRC_SHIFT = 8, + OFPFW_NW_SRC_BITS = 6, + OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, + OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, + + /* IP destination address wildcard bit count. Same format as source. */ + OFPFW_NW_DST_SHIFT = 14, + OFPFW_NW_DST_BITS = 6, + OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, + OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, + + OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ + OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ + + /* Wildcard all fields. */ + OFPFW_ALL = ((1 << 22) - 1) +}; + +/* The wildcards for ICMP type and code fields use the transport source + * and destination port fields, respectively. */ +#define OFPFW_ICMP_TYPE OFPFW_TP_SRC +#define OFPFW_ICMP_CODE OFPFW_TP_DST + +/* Values below this cutoff are 802.3 packets and the two bytes + * following MAC addresses are used as a frame length. Otherwise, the + * two bytes are used as the Ethernet type. + */ +#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 + +/* Value of dl_type to indicate that the frame does not include an + * Ethernet type. + */ +#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * special conditions. All ones indicates that no VLAN id was set. + */ +#define OFP_VLAN_NONE 0xffff + +/* Fields to match against flows */ +struct ofp_match { + uint32_t wildcards; /* Wildcard fields. */ + uint16_t in_port; /* Input switch port. */ + uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t pad1[1]; /* Align to 64-bits */ + uint16_t dl_type; /* Ethernet frame type. */ + uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto; /* IP protocol or lower 8 bits of + * ARP opcode. */ + uint8_t pad2[2]; /* Align to 64-bits */ + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ +}; +OFP_ASSERT(sizeof(struct ofp_match) == 40); + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +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_EMERG = 1 << 2 /* Remark this is for emergency. */ +}; + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_fluid_header header; + struct ofp_match match; /* Fields to match */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + /* Flow actions. */ + uint16_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 -1). + Not meaningful for OFPFC_DELETE*. */ + uint16_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_NONE + indicates no restriction. */ + uint16_t flags; /* One of OFPFF_*. */ + struct ofp_action_header actions[0]; /* The action length is inferred + from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); + +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + OFPRR_DELETE /* Evicted by a DELETE flow mod. */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_fluid_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t pad[1]; /* Align to 32-bits. */ + + 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. */ + uint8_t pad2[2]; /* Align to 64-bits. */ + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); + +/* 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, /* Hello protocol failed. */ + OFPET_BAD_REQUEST, /* Request was not understood. */ + OFPET_BAD_ACTION, /* Error in action description. */ + OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ + OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ + OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ +}; + +/* ofp_fluid_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, /* No compatible version. */ + OFPHFC_EPERM /* Permissions error. */ +}; + +/* ofp_fluid_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, /* ofp_fluid_header.version not supported. */ + OFPBRC_BAD_TYPE, /* ofp_fluid_header.type not supported. */ + OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ + OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header + * or ofp_stats_request or ofp_stats_reply). */ + OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ + OFPBRC_EPERM, /* Permissions error. */ + OFPBRC_BAD_LEN, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ +}; + +/* ofp_fluid_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, /* Unknown action type. */ + OFPBAC_BAD_LEN, /* Length problem in actions. */ + OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ + OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ + OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ + OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ + OFPBAC_EPERM, /* Permissions error. */ + OFPBAC_TOO_MANY, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE /* Problem validating output queue. */ +}; + +/* ofp_fluid_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_ALL_TABLES_FULL, /* Flow not added because of full tables. */ + OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with + * CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM, /* Permissions error. */ + OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard + * timeout. */ + OFPFMFC_BAD_COMMAND, /* Unknown command. */ + OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in + * the order specified. */ +}; + +/* ofp_fluid_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, /* Specified port does not exist. */ + OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ +}; + +/* 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, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ + OFPQOFC_EPERM /* Permissions error. */ +}; + +enum ofp_stats_types { + /* Description of this OpenFlow switch. + * The request body is empty. + * The reply body is struct ofp_desc_stats. */ + OFPST_DESC, + + /* Individual flow statistics. + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ + OFPST_FLOW, + + /* Aggregate flow statistics. + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ + OFPST_AGGREGATE, + + /* Flow table statistics. + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ + OFPST_TABLE, + + /* Physical port statistics. + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ + OFPST_PORT, + + /* Queue statistics for a port + * The request body defines the port + * The reply body is an array of struct ofp_queue_stats */ + OFPST_QUEUE, + + /* Vendor extension. + * The request and reply bodies begin with a 32-bit vendor ID, which takes + * the same form as in "struct ofp_vendor_header". The request and reply + * bodies are otherwise vendor-defined. */ + OFPST_VENDOR = 0xffff +}; + +struct ofp_stats_request { + struct ofp_fluid_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ + uint8_t body[0]; /* Body of the request. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); + +enum ofp_stats_reply_flags { + OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_stats_reply { + struct ofp_fluid_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REPLY_* flags. */ + uint8_t body[0]; /* Body of the reply. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); + +/* Body for ofp_stats_request of type OFPST_FLOW. */ +struct ofp_flow_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); + +/* Body of reply to OFPST_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; + struct ofp_match match; /* Description of fields. */ + 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. Only meaningful + when this is not an exact-match 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_action_header actions[0]; /* Actions. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); + +/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ +struct ofp_aggregate_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); + +/* Body of reply to OFPST_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); + +/* Body of reply to OFPST_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. */ + char name[OFP_FLUID_MAX_TABLE_NAME_LEN]; + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + uint32_t max_entries; /* Max number of entries supported. */ + 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) == 64); + +/* Body for ofp_stats_request of type OFPST_PORT. */ +struct ofp_port_stats_request { + uint16_t port_no; /* OFPST_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_NONE). */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* Body of reply to OFPST_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint16_t port_no; + uint8_t pad[6]; /* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); + +/* Vendor extension. */ +struct ofp_vendor_header { + struct ofp_fluid_header header; /* Type OFPT_VENDOR. */ + uint32_t vendor; /* Vendor ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by OpenFlow + * consortium. */ + /* Vendor-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); + +enum ofp_queue_properties { + OFPQT_NONE = 0, /* No property defined for queue (default). */ + OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ +/* Other types should be added here + * (i.e. max rate, precedence, etc). */ +}; + +/* 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_queue_prop_min_rate) == 16); + +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[2]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_fluid_header header; + uint16_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_FLUID_MAX) */ + uint8_t pad[2]; /* 32-bit alignment. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); + +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_fluid_header header; + uint16_t port; + uint8_t pad[6]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); + +struct ofp_queue_stats_request { + uint16_t port_no; /* All ports if OFPT_ALL. */ + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* All queues if OFPQ_FLUID_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); + +struct ofp_queue_stats { + uint16_t port_no; + uint8_t pad[2]; /* Align to 32-bits. */ + 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); + +} + +} //End of namespace fluid_msg +#endif /* openflow/openflow.h */ diff --git a/include/libfluid-msg/of10msg.hh b/include/libfluid-msg/of10msg.hh new file mode 100644 index 00000000..2e26cc25 --- /dev/null +++ b/include/libfluid-msg/of10msg.hh @@ -0,0 +1,865 @@ +#ifndef OF10MSG_H +#define OF10MSG_H 1 + +#include "ofcommon/msg.hh" +#include "of10/of10common.hh" +#include "of10/of10action.hh" + +/** + Classes for creating and parsing OpenFlow messages. + */ +namespace fluid_msg { + +/** + Classes for creating and parsing OpenFlow 1.0 messages. + */ +namespace of10 { + +/** + OpenFlow 1.0 OFPT_HELLO message. + */ +class Hello: public OFMsg { +public: + Hello(); + Hello(uint32_t xid); + ~Hello() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_ERROR message. + */ +class Error: public ErrorCommon { +public: + Error(); + Error(uint32_t xid, uint16_t err_type, uint16_t code); + Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len); + ~Error() { + } +}; + +/** + OpenFlow 1.0 OFPT_ECHO_REQUEST message. + */ +class EchoRequest: public EchoCommon { +public: + EchoRequest() + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REQUEST) { + } + EchoRequest(uint32_t xid); + ~EchoRequest() { + } +}; + +/** + OpenFlow 1.0 OFPT_ECHO_REPLY message. + */ +class EchoReply: public EchoCommon { +public: + EchoReply() + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REPLY) { + } + EchoReply(uint32_t xid); + ~EchoReply() { + } +}; + +/** + OpenFlow 1.0 OFPT_VENDOR message. + Vendor messages should inherit from this class. + */ +class Vendor: public OFMsg { +protected: + uint32_t vendor_; +public: + Vendor(); + Vendor(uint32_t xid, uint32_t vendor); + ~Vendor() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPT_FEATURES_REQUEST message. + */ +class FeaturesRequest: public OFMsg { +public: + FeaturesRequest(); + FeaturesRequest(uint32_t xid); + ~FeaturesRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_FEATURES_REPLY message. + */ +class FeaturesReply: public FeaturesReplyCommon { +private: + uint32_t actions_; + std::vector ports_; +public: + FeaturesReply(); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint32_t capabilities, uint32_t actions); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint32_t capabilities, uint32_t actions, + std::vector ports); + bool operator==(const FeaturesReply &other) const; + bool operator!=(const FeaturesReply &other) const; + ~FeaturesReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t actions() { + return this->actions_; + } + std::vector ports() { + return this->ports_; + } + void actions(uint32_t actions) { + this->actions_ = actions; + } + void ports(std::vector ports); + size_t ports_length(); + void add_port(of10::Port port); +}; + +/** + OpenFlow 1.0 OFPT_GET_CONFIG_REQUEST message. + */ +class GetConfigRequest: public OFMsg { +public: + GetConfigRequest(); + GetConfigRequest(uint32_t xid); + ~GetConfigRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_GET_CONFIG_REPLY message. + */ +class GetConfigReply: public SwitchConfigCommon { +public: + GetConfigReply(); + GetConfigReply(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~GetConfigReply() { + } +}; + +/** + OpenFlow 1.0 OFPT_SET_CONFIG message. + */ +class SetConfig: public SwitchConfigCommon { +public: + SetConfig(); + SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~SetConfig() { + } +}; + +/** + OpenFlow 1.0 OFPT_FLOW_MOD message. + */ +class FlowMod: public FlowModCommon { +private: + uint16_t command_; + uint16_t out_port_; + of10::Match match_; + ActionList actions_; +public: + FlowMod(); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, + of10::Match match); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, + of10::Match match, ActionList actions); + ~FlowMod() { + } + bool operator==(const FlowMod &other) const; + bool operator!=(const FlowMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command(){ + return this->command_; + } + of10::Match match() { + return this->match_; + } + ActionList actions() { + return this->actions_; + } + uint16_t out_port() { + return this->out_port_; + } + void command(uint16_t command){ + this->command_ = command; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } + void match(const of10::Match& match) { + this->match_ = match; + } + void actions(const ActionList &actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +/** + OpenFlow 1.0 OFPT_PACKET_OUT message. + */ +class PacketOut: public PacketOutCommon { +private: + uint16_t in_port_; +public: + PacketOut(); + PacketOut(uint32_t xid, uint32_t buffer_id, uint16_t in_port); + ~PacketOut() { + } + bool operator==(const PacketOut &other) const; + bool operator!=(const PacketOut &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t in_port() { + return this->in_port_; + } + void in_port(uint16_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.0 OFPT_PACKET_IN message. + */ +class PacketIn: public PacketInCommon { +private: + uint16_t in_port_; +public: + PacketIn(); + PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t in_port, + uint16_t total_len, uint8_t reason); + ~PacketIn() { + } + bool operator==(const PacketIn &other) const; + bool operator!=(const PacketIn &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t in_port() { + return this->in_port_; + } + void in_port(uint16_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.0 OFPT_FLOW_REMOVED message. + */ +class FlowRemoved: public FlowRemovedCommon { +private: + of10::Match match_; +public: + FlowRemoved(); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count, + of10::Match match); + ~FlowRemoved() { + } + bool operator==(const FlowRemoved &other) const; + bool operator!=(const FlowRemoved &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + void match(of10::Match match) { + this->match_ = match; + } +}; + +/** + OpenFlow 1.0 OFPT_PORT_STATUS message. + */ +class PortStatus: public PortStatusCommon { +private: + of10::Port desc_; +public: + PortStatus(); + PortStatus(uint32_t xid, uint8_t reason, of10::Port desc); + ~PortStatus() { + } + bool operator==(const PortStatus &other) const; + bool operator!=(const PortStatus &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Port desc() { + return this->desc_; + } + void desc(of10::Port desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.0 OFPT_PORT_MOD message. + */ +class PortMod: public PortModCommon { +private: + uint16_t port_no_; +public: + PortMod(); + PortMod(uint32_t xid, uint16_t port_no, EthAddress hw_addr, uint32_t config, + uint32_t mask, uint32_t advertise); + ~PortMod() { + } + bool operator==(const PortMod &other) const; + bool operator!=(const PortMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.0 OFPT_STATS_REQUEST message header. Stats request + messages should inherit from this class. + */ +class StatsRequest: public OFMsg { +protected: + uint16_t stats_type_; + uint16_t flags_; +public: + StatsRequest(); + StatsRequest(uint16_t); + StatsRequest(uint32_t xid, uint16_t type, uint16_t flags); + ~StatsRequest() { + } + bool operator==(const StatsRequest &other) const; + bool operator!=(const StatsRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t stats_type() { + return this->stats_type_; + } + uint16_t flags() { + return this->flags_; + } + void stats_type(uint16_t type) { + this->stats_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.0 OFPT_STATS_REPLY message header. Stats reply + messages should inherit from this class. + */ +class StatsReply: public OFMsg { +protected: + uint16_t stats_type_; + uint16_t flags_; +public: + StatsReply(); + StatsReply(uint16_t type); + StatsReply(uint32_t xid, uint16_t type, uint16_t flags); + ~StatsReply() { + } + bool operator==(const StatsReply &other) const; + bool operator!=(const StatsReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t stats_type() { + return this->stats_type_; + } + uint16_t flags() { + return this->flags_; + } + void stats_type(uint16_t type) { + this->stats_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.0 OFPST_DESC multipart request. + */ +class StatsRequestDesc: public StatsRequest { +public: + StatsRequestDesc(); + StatsRequestDesc(uint32_t xid, uint16_t flags); + ~StatsRequestDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPST_DESC multipart reply. + */ +class StatsReplyDesc: public StatsReply { +private: + SwitchDesc desc_; +public: + StatsReplyDesc(); + StatsReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc); + StatsReplyDesc(uint32_t xid, uint16_t flags, std::string mfr_desc, + std::string hw_desc, std::string sw_desc, std::string serial_num, + std::string dp_desc); + ~StatsReplyDesc() { + } + bool operator==(const StatsReplyDesc &other) const; + bool operator!=(const StatsReplyDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + SwitchDesc desc() { + return this->desc_; + } + void desc(SwitchDesc desc); +}; + +/** + OpenFlow 1.0 OFPST_FLOW multipart request. + */ +class StatsRequestFlow: public StatsRequest { +private: + of10::Match match_; + uint8_t table_id_; + uint16_t out_port_; +public: + StatsRequestFlow(); + StatsRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint16_t out_port); + StatsRequestFlow(uint32_t xid, uint16_t flags, of10::Match match, + uint8_t table_id, uint16_t out_port); + virtual ~StatsRequestFlow() { + } + bool operator==(const StatsRequestFlow &other) const; + bool operator!=(const StatsRequestFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint16_t out_port() { + return this->out_port_; + } + void match(of10::Match match) { + this->match_ = match; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } +}; + +/** + OpenFlow 1.0 OFPST_FLOW multipart reply. + */ +class StatsReplyFlow: public StatsReply { +private: + std::vector flow_stats_; +public: + StatsReplyFlow(); + StatsReplyFlow(uint32_t xid, uint16_t flags); + StatsReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats); + virtual ~StatsReplyFlow() { + } + bool operator==(const StatsReplyFlow &other) const; + bool operator!=(const StatsReplyFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector flow_stats() { + return this->flow_stats_; + } + void flow_stats(std::vector flow_stats); + void add_flow_stats(of10::FlowStats); +}; + +/** + OpenFlow 1.0 OFPST_AGGREGATE multipart request. + */ +class StatsRequestAggregate: public StatsRequest { +private: + of10::Match match_; + uint8_t table_id_; + uint16_t out_port_; +public: + StatsRequestAggregate(); + StatsRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint16_t out_port); + StatsRequestAggregate(uint32_t xid, uint16_t flags, of10::Match match, + uint8_t table_id, uint16_t out_port); + ~StatsRequestAggregate() { + } + bool operator==(const StatsRequestAggregate &other) const; + bool operator!=(const StatsRequestAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint16_t out_port() { + return this->out_port_; + } + void match(of10::Match match) { + this->match_ = match; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } +}; + +/** + OpenFlow 1.0 OFPST_AGGREGATE multipart reply. + */ +class StatsReplyAggregate: public StatsReply { +private: + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t flow_count_; +public: + StatsReplyAggregate(); + StatsReplyAggregate(uint32_t xid, uint16_t flags, uint64_t packet_count, + uint64_t byte_count, uint32_t flow_count); + ~StatsReplyAggregate() { + } + bool operator==(const StatsReplyAggregate &other) const; + bool operator!=(const StatsReplyAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t flow_count() { + return this->flow_count_; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void flow_count(uint32_t flow_count) { + this->flow_count_ = flow_count; + } +}; + +/** + OpenFlow 1.0 OFPST_TABLE multipart request. + */ +class StatsRequestTable: public StatsRequest { +public: + StatsRequestTable(); + StatsRequestTable(uint32_t xid, uint16_t flags); + ~StatsRequestTable() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPST_TABLE multipart reply. + */ +class StatsReplyTable: public StatsReply { +private: + std::vector table_stats_; +public: + StatsReplyTable(); + StatsReplyTable(uint32_t xid, uint16_t flags); + StatsReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats); + ~StatsReplyTable() { + } + bool operator==(const StatsReplyTable &other) const; + bool operator!=(const StatsReplyTable &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_stats() { + return this->table_stats_; + } + void table_stats(std::vector table_stats); + void add_table_stat(of10::TableStats stat); +}; + +/** + OpenFlow 1.0 OFPST_PORT_STATS multipart request. + */ +class StatsRequestPort: public StatsRequest { +private: + uint16_t port_no_; +public: + StatsRequestPort(); + StatsRequestPort(uint32_t xid, uint16_t flags, uint16_t port_no); + ~StatsRequestPort() { + } + bool operator==(const StatsRequestPort &other) const; + bool operator!=(const StatsRequestPort &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.0 OFPST_PORT_STATS multipart reply. + */ +class StatsReplyPort: public StatsReply { +private: + std::vector port_stats_; +public: + StatsReplyPort(); + StatsReplyPort(uint32_t xid, uint16_t flags); + StatsReplyPort(uint32_t xid, uint16_t flags, + std::vector port_stats); + ~StatsReplyPort() { + } + bool operator==(const StatsReplyPort &other) const; + bool operator!=(const StatsReplyPort &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector port_stats() { + return this->port_stats_; + } + void port_stats(std::vector port_stats); + void add_port_stat(of10::PortStats stat); +}; + +/** + OpenFlow 1.0 OFPST_QUEUE multipart request. + */ +class StatsRequestQueue: public StatsRequest { +private: + uint16_t port_no_; + uint32_t queue_id_; +public: + StatsRequestQueue(); + StatsRequestQueue(uint32_t xid, uint16_t flags, uint16_t port_no, + uint32_t queue_id); + ~StatsRequestQueue() { + } + bool operator==(const StatsRequestQueue &other) const; + bool operator!=(const StatsRequestQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +/** + OpenFlow 1.0 OFPST_QUEUE multipart reply. + */ +class StatsReplyQueue: public StatsReply { +private: + std::vector queue_stats_; +public: + StatsReplyQueue(); + StatsReplyQueue(uint32_t xid, uint16_t flags); + StatsReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats); + ~StatsReplyQueue() { + } + bool operator==(const StatsReplyQueue &other) const; + bool operator!=(const StatsReplyQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->queue_stats_; + } + void queue_stats(std::vector queue_stats_); + void add_queue_stat(of10::QueueStats stat); +}; + +/** + OpenFlow 1.0 OFPST_VENDOR stats request. + Vendor stats request messages should inherit from this class. + */ +class StatsRequestVendor: public StatsRequest { +protected: + uint32_t vendor_; +public: + StatsRequestVendor(); + StatsRequestVendor(uint32_t xid, uint16_t flags, uint32_t vendor); + virtual ~StatsRequestVendor() { + } + bool operator==(const StatsRequestVendor &other) const; + bool operator!=(const StatsRequestVendor &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPST_VENDOR stats reply. + Vendor stats reply messages should inherit from this class. + */ +class StatsReplyVendor: public StatsReply { +protected: + uint32_t vendor_; +public: + StatsReplyVendor(); + StatsReplyVendor(uint32_t xid, uint16_t flags, uint32_t vendor); + virtual ~StatsReplyVendor() { + } + bool operator==(const StatsReplyVendor &other) const; + bool operator!=(const StatsReplyVendor &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPT_QUEUE_GET_CONFIG_REQUEST message. + */ +class QueueGetConfigRequest: public OFMsg { +private: + uint16_t port_; +public: + QueueGetConfigRequest(); + QueueGetConfigRequest(uint32_t xid, uint16_t port); + ~QueueGetConfigRequest() { + } + bool operator==(const QueueGetConfigRequest &other) const; + bool operator!=(const QueueGetConfigRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + void port(uint16_t port) { + this->port_ = port; + } +}; + +/** + OpenFlow 1.0 OFPT_QUEUE_GET_CONFIG_REPLY message. + */ +class QueueGetConfigReply: public OFMsg { +private: + uint16_t port_; + std::list queues_; +public: + QueueGetConfigReply(); + QueueGetConfigReply(uint32_t xid, uint16_t port); + QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues); + ~QueueGetConfigReply() { + } + bool operator==(const QueueGetConfigReply &other) const; + bool operator!=(const QueueGetConfigReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + std::list queues() { + return this->queues_; + } + void port(uint32_t port) { + this->port_ = port; + } + void queues(std::list queues); + void add_queue(PacketQueue queue); + size_t queues_len(); +}; + +/** + OpenFlow 1.0 OFPT_BARRIER_REQUEST message + */ +class BarrierRequest: public OFMsg { +public: + BarrierRequest(); + BarrierRequest(uint32_t xid); + ~BarrierRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.0 OFPT_BARRIER_REPLY message*/ +class BarrierReply: public OFMsg { +public: + BarrierReply(); + BarrierReply(uint32_t xid); + ~BarrierReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +} //end of namespace of10 +} //End of namespace fluid_msg + +#endif + diff --git a/include/libfluid-msg/of13/of13action.hh b/include/libfluid-msg/of13/of13action.hh new file mode 100644 index 00000000..c4a4540c --- /dev/null +++ b/include/libfluid-msg/of13/of13action.hh @@ -0,0 +1,404 @@ +#ifndef OF13ACTION_H +#define OF13ACTION_H + +#include "../ofcommon/action.hh" +#include "of13match.hh" + +namespace fluid_msg { + +namespace of13 { + +class OutputAction: public Action { +private: + uint32_t port_; + uint16_t max_len_; + const uint16_t set_order_; +public: + OutputAction(); + OutputAction(uint32_t port, uint16_t max_len); + ~OutputAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual OutputAction* clone() { + return new OutputAction(*this); + } + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } + uint16_t max_len() { + return this->max_len_; + } + void max_len(uint16_t max_len) { + this->max_len_ = max_len; + } +}; + +class CopyTTLOutAction: public Action { +private: + const uint16_t set_order_; +public: + CopyTTLOutAction(); + ~CopyTTLOutAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual CopyTTLOutAction* clone() { + return new CopyTTLOutAction(*this); + } +}; + +class CopyTTLInAction: public Action { +private: + const uint16_t set_order_; +public: + CopyTTLInAction(); + ~CopyTTLInAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual CopyTTLInAction* clone() { + return new CopyTTLInAction(*this); + } +}; + +class SetMPLSTTLAction: public Action { +private: + uint8_t mpls_ttl_; + const uint16_t set_order_; +public: + SetMPLSTTLAction(); + SetMPLSTTLAction(uint8_t mpls_ttl); + ~SetMPLSTTLAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t mpls_ttl() { + return this->mpls_ttl_; + } + void mpls_ttl(uint8_t mpls_ttl) { + this->mpls_ttl_ = mpls_ttl; + } + virtual SetMPLSTTLAction* clone() { + return new SetMPLSTTLAction(*this); + } +}; + +class DecMPLSTTLAction: public Action { +private: + const uint16_t set_order_; +public: + DecMPLSTTLAction(); + ~DecMPLSTTLAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual DecMPLSTTLAction* clone() { + return new DecMPLSTTLAction(*this); + } +}; + +class PushVLANAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushVLANAction(); + PushVLANAction(uint16_t ethertype); + ~PushVLANAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushVLANAction* clone() { + return new PushVLANAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopVLANAction: public Action { +private: + const uint16_t set_order_; +public: + PopVLANAction(); + ~PopVLANAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopVLANAction* clone() { + return new PopVLANAction(*this); + } +}; + +class PushMPLSAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushMPLSAction(); + PushMPLSAction(uint16_t ethertype); + ~PushMPLSAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushMPLSAction* clone() { + return new PushMPLSAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopMPLSAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PopMPLSAction(); + PopMPLSAction(uint16_t ethertype); + ~PopMPLSAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopMPLSAction* clone() { + return new PopMPLSAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class SetQueueAction: public Action { +private: + uint32_t queue_id_; + const uint16_t set_order_; +public: + SetQueueAction(); + SetQueueAction(uint32_t queue_id); + ~SetQueueAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetQueueAction* clone() { + return new SetQueueAction(*this); + } + uint32_t queue_id() { + return this->queue_id_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +class GroupAction: public Action { +private: + uint32_t group_id_; + const uint16_t set_order_; +public: + GroupAction(); + GroupAction(uint32_t group_id); + ~GroupAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual GroupAction* clone() { + return new GroupAction(*this); + } + uint32_t group_id() { + return this->group_id_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } +}; + +class SetNWTTLAction: public Action { +private: + uint8_t nw_ttl_; + const uint16_t set_order_; +public: + SetNWTTLAction(); + SetNWTTLAction(uint8_t nw_ttl); + ~SetNWTTLAction() { + } + ; + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWTTLAction* clone() { + return new SetNWTTLAction(*this); + } + uint8_t nw_ttl() { + return this->nw_ttl_; + } + void nw_ttl(uint8_t nw_ttl) { + this->nw_ttl_ = nw_ttl; + } +}; + +class DecNWTTLAction: public Action { +private: + const uint16_t set_order_; +public: + DecNWTTLAction(); + ~DecNWTTLAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual DecNWTTLAction* clone() { + return new DecNWTTLAction(*this); + } +}; + +class SetFieldAction: public Action { +private: + OXMTLV* field_; + const uint16_t set_order_; +public: + SetFieldAction(); + SetFieldAction(OXMTLV* field); + SetFieldAction(const SetFieldAction &other); + ~SetFieldAction(); + virtual bool equals(const Action & other); + SetFieldAction& operator=(SetFieldAction other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetFieldAction* clone() { + return new SetFieldAction(*this); + } + OXMTLV* field(); + void field(OXMTLV* field); + friend void swap(SetFieldAction& first, SetFieldAction& second); +}; + +class PushPBBAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushPBBAction(); + PushPBBAction(uint16_t ethertype); + ~PushPBBAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushPBBAction* clone() { + return new PushPBBAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopPBBAction: public Action { +private: + const uint16_t set_order_; +public: + PopPBBAction(); + ~PopPBBAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopPBBAction* clone() { + return new PopPBBAction(*this); + } +}; + +class ExperimenterAction: public Action { +protected: + uint32_t experimenter_; +public: + ExperimenterAction(); + ExperimenterAction(uint32_t experimenter); + ~ExperimenterAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual ExperimenterAction* clone() { + return new ExperimenterAction(*this); + } + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/of13common.hh b/include/libfluid-msg/of13/of13common.hh new file mode 100644 index 00000000..18f6ed45 --- /dev/null +++ b/include/libfluid-msg/of13/of13common.hh @@ -0,0 +1,769 @@ +#ifndef OF13OPENFLOW_COMMON_H +#define OF13OPENFLOW_COMMON_H 1 + +#include +#include + +#include "../ofcommon/common.hh" +#include "../util/util.h" +#include "openflow-13.h" +#include "of13action.hh" +#include "of13instruction.hh" + +namespace fluid_msg { + +namespace of13 { + +class HelloElem { +protected: + uint16_t type_; + uint16_t length_; +public: + HelloElem() { + } + HelloElem(uint16_t type, uint16_t length); + ~HelloElem() { + } + bool operator==(const HelloElem &other) const; + bool operator!=(const HelloElem &other) const; + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } +}; + +class HelloElemVersionBitmap: public HelloElem { +private: + std::list bitmaps_; +public: + HelloElemVersionBitmap() + : HelloElem(of13::OFPHET_VERSIONBITMAP, + sizeof(struct of13::ofp_hello_elem_versionbitmap)) { + } + HelloElemVersionBitmap(std::list bitmap); + bool operator==(const HelloElemVersionBitmap &other) const; + bool operator!=(const HelloElemVersionBitmap &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t *data); + std::list bitmaps() { + return this->bitmaps_; + } + void bitmaps(std::list bitmaps) { + this->bitmaps_ = bitmaps; + } + void add_bitmap(uint32_t bitmap); +}; + +class Port: public PortCommon { +private: + uint32_t port_no_; + uint32_t curr_speed_; + uint32_t max_speed_; +public: + Port(); + Port(uint32_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer, uint32_t curr_speed, + uint32_t max_speed); + ~Port() { + } + bool operator==(const Port &other) const; + bool operator!=(const Port &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t curr_speed() { + return this->curr_speed_; + } + uint32_t max_speed() { + return this->max_speed_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void curr_speed(uint32_t curr_speed) { + this->curr_speed_ = curr_speed; + } + void max_speed(uint32_t max_speed) { + this->max_speed_ = max_speed; + } +}; + +class QueuePropMinRate: public QueuePropRate { +public: + QueuePropMinRate() + : QueuePropRate(of13::OFPQT_MIN_RATE) { + } + QueuePropMinRate(uint16_t rate); + ~QueuePropMinRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMinRate* clone() { + return new QueuePropMinRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class QueuePropMaxRate: public QueuePropRate { +public: + QueuePropMaxRate() + : QueuePropRate(of13::OFPQT_MAX_RATE) { + } + QueuePropMaxRate(uint16_t rate); + ~QueuePropMaxRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMaxRate* clone() { + return new QueuePropMaxRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class QueueExperimenter: public QueueProperty { +protected: + uint32_t experimenter_; +public: + QueueExperimenter() { + } + QueueExperimenter(uint32_t experimenter); + ~QueueExperimenter() { + } + virtual QueueExperimenter* clone() { + return new QueueExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t get_experimenter() { + return this->experimenter_; + } + void set_experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +/* Queue description*/ +class PacketQueue: public PacketQueueCommon { +private: + uint32_t port_; +public: + PacketQueue(); + PacketQueue(uint32_t queue_id, uint32_t port); + PacketQueue(uint32_t queue_id, uint32_t port, QueuePropertyList properties); + ~PacketQueue() { + } + bool operator==(const PacketQueue &other) const; + bool operator!=(const PacketQueue &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } +}; + +class Bucket { +private: + uint16_t length_; + uint16_t weight_; + uint32_t watch_port_; + uint32_t watch_group_; + ActionSet actions_; +public: + Bucket(); + Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group); + Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group, + ActionSet actions); + ~Bucket() { + } + bool operator==(const Bucket &other) const; + bool operator!=(const Bucket &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t len() { + return this->length_; + } + uint16_t weight() { + return this->weight_; + } + uint32_t watch_port() { + return this->watch_port_; + } + uint32_t watch_group() { + return this->watch_group_; + } + ActionSet get_actions() { + return this->actions_; + } + void weight(uint16_t weight) { + this->weight_ = weight; + } + void watch_port(uint32_t watch_port) { + this->watch_port_ = watch_port; + } + void watch_group(uint32_t watch_group) { + this->watch_group_ = watch_group; + } + void actions(ActionSet actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class FlowStats: public FlowStatsCommon { +private: + uint16_t flags_; + of13::Match match_; + InstructionSet instructions_; +public: + FlowStats(); + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint16_t flags, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count); + ~FlowStats() { + } + bool operator==(const FlowStats &other) const; + bool operator!=(const FlowStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t get_flags() { + return this->flags_; + } + void set_flags(uint16_t flags) { + this->flags_ = flags; + } + void match(of13::Match match); + of13::Match match() { + return this->match_; + } + OXMTLV * get_oxm_field(uint8_t field); + void instructions(InstructionSet instructions); + void add_instruction(Instruction* inst); + InstructionSet instructions() { + return this->instructions_; + } +}; + +class TableStats: public TableStatsCommon { +public: + TableStats(); + TableStats(uint8_t table_id, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count); + ~TableStats() { + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class PortStats: public PortStatsCommon { +private: + uint32_t port_no_; + uint32_t duration_sec_; + uint32_t duration_nsec_; +public: + PortStats(); + PortStats(uint32_t port_no, struct port_rx_tx_stats tx_stats, + struct port_err_stats err_stats, uint64_t collisions, + uint32_t duration_sec, uint32_t duration_nsec); + ~PortStats() { + } + bool operator==(const PortStats &other) const; + bool operator!=(const PortStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } +}; + +class QueueStats: public QueueStatsCommon { +private: + uint32_t port_no_; + uint32_t duration_sec_; + uint32_t duration_nsec_; +public: + QueueStats(); + QueueStats(uint32_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors, uint32_t duration_sec, + uint32_t duration_nsec); + ~QueueStats() { + } + bool operator==(const QueueStats &other) const; + bool operator!=(const QueueStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } +}; + +class BucketStats { +private: + uint64_t packet_count_; + uint64_t byte_count_; +public: + BucketStats(); + BucketStats(uint64_t packet_count, uint64_t byte_count); + ~BucketStats() { + } + bool operator==(const BucketStats &other) const; + bool operator!=(const BucketStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } +}; + +class GroupStats { +private: + uint16_t length_; + uint32_t group_id_; + uint32_t ref_count_; + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + std::vector bucket_stats_; +public: + GroupStats() + : length_(sizeof(struct of13::ofp_group_stats)) { + } + GroupStats(uint32_t group_id, uint32_t ref_count, uint64_t packet_count, + uint64_t byte_count, uint32_t duration_sec, uint32_t duration_nsec); + GroupStats(uint32_t group_id, uint32_t ref_count, uint64_t packet_count, + uint64_t byte_count, uint32_t duration_sec, uint32_t duration_nsec, + std::vector bucket_stats); + ~GroupStats() { + } + bool operator==(const GroupStats &other) const; + bool operator!=(const GroupStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint32_t group_id() { + return this->group_id_; + } + uint32_t ref_count() { + return this->ref_count_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void ref_count(uint32_t ref_count) { + this->ref_count_ = ref_count; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint64_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void bucket_stats(std::vector bucket_stats); + void add_bucket_stat(BucketStats stat); +}; + +class GroupDesc { +private: + uint16_t length_; + uint8_t type_; + uint32_t group_id_; + std::vector buckets_; +public: + GroupDesc() + : length_(sizeof(struct of13::ofp_group_desc_stats)) { + } + GroupDesc(uint8_t type, uint32_t group_id); + GroupDesc(uint8_t type, uint32_t group_id, + std::vector buckets); + ~GroupDesc() { + } + bool operator==(const GroupDesc &other) const; + bool operator!=(const GroupDesc &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint8_t type() { + return this->type_; + } + uint32_t group_id() { + return this->group_id_; + } + std::vector buckets() { + return this->buckets_; + } + void type(uint8_t type) { + this->type_ = type; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void buckets(std::vector buckets); + void add_bucket(Bucket bucket); + size_t buckets_len(); +}; + +class GroupFeatures { +private: + uint32_t types_; + uint32_t capabilities_; + uint32_t max_groups_[4]; + uint32_t actions_[4]; +public: + GroupFeatures() { + } + GroupFeatures(uint32_t types, uint32_t capabilities, uint32_t max_groups[4], + uint32_t actions[4]); + ~GroupFeatures() { + } + bool operator==(const GroupFeatures &other) const; + bool operator!=(const GroupFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t types() { + return this->types_; + } + uint32_t capabilities() { + return this->capabilities_; + } + uint32_t* max_groups() { + return this->max_groups_; + } + uint32_t* actions() { + return this->actions_; + } + void types(uint32_t types) { + this->types_ = types; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } + void max_groups(uint32_t max_groups[4]) { + memcpy(this->max_groups_, max_groups, 16); + } + void actions(uint32_t actions[4]) { + memcpy(this->actions_, actions, 16); + } +}; + +class TableFeatureProp { +protected: + uint16_t type_; + uint16_t length_; + uint8_t padding_; +public: + TableFeatureProp() + : length_(sizeof(struct ofp_table_feature_prop_header)), + padding_(4) { + } + TableFeatureProp(uint16_t type); + virtual ~TableFeatureProp() { + } + virtual bool equals(const TableFeatureProp & other); + virtual bool operator==(const TableFeatureProp &other) const; + virtual bool operator!=(const TableFeatureProp &other) const; + virtual TableFeatureProp* clone() { + return new TableFeatureProp(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + uint8_t padding() { + return this->padding_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static bool delete_all(TableFeatureProp * prop) { + delete prop; + return true; + } +}; + +class TableFeaturePropInstruction: public TableFeatureProp { +private: + std::vector instruction_ids_; +public: + TableFeaturePropInstruction() + : TableFeatureProp() { + } + TableFeaturePropInstruction(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropInstruction(uint16_t type, + std::vector instruction_ids); + ~TableFeaturePropInstruction() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropInstruction* clone() { + return new TableFeaturePropInstruction(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector instruction_ids() { + return this->instruction_ids_; + } + void instruction_ids(std::vector instruction_ids); +}; + +class TableFeaturePropNextTables: public TableFeatureProp { +private: + std::vector next_table_ids_; +public: + TableFeaturePropNextTables() + : TableFeatureProp() { + } + TableFeaturePropNextTables(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropNextTables(uint16_t type, + std::vector next_table_ids); + ~TableFeaturePropNextTables() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropNextTables* clone() { + return new TableFeaturePropNextTables(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector next_table_ids() { + return this->next_table_ids_; + } + void table_ids(std::vector table_ids); +}; + +class TableFeaturePropActions: public TableFeatureProp { +private: + std::vector action_ids_; +public: + TableFeaturePropActions() + : TableFeatureProp() { + } + TableFeaturePropActions(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropActions(uint16_t type, std::vector action_ids); + ~TableFeaturePropActions() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropActions* clone() { + return new TableFeaturePropActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector action_ids() { + return this->action_ids_; + } + void action_ids(std::vector action_ids); +}; + +class TableFeaturePropOXM: public TableFeatureProp { +private: + std::vector oxm_ids_; +public: + TableFeaturePropOXM() + : TableFeatureProp() { + } + TableFeaturePropOXM(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropOXM(uint16_t type, std::vector oxm_ids); + ~TableFeaturePropOXM() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropOXM* clone() { + return new TableFeaturePropOXM(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + void oxm_ids(std::vector oxm_ids); +}; + +class TableFeaturePropExperimenter: public TableFeatureProp { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + TableFeaturePropExperimenter() + : TableFeatureProp() { + } + TableFeaturePropExperimenter(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropExperimenter(uint16_t type, uint32_t experimenter, + uint32_t exp_type); + ~TableFeaturePropExperimenter() { + } + virtual bool equals(const TableFeatureProp & other); + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class TablePropertiesList { +private: + uint16_t length_; + std::list property_list_; +public: + TablePropertiesList() + : length_(0) { + } + TablePropertiesList(std::list property_list); + TablePropertiesList(const TablePropertiesList &other); + TablePropertiesList& operator=(TablePropertiesList other); + ~TablePropertiesList(); + bool operator==(const TablePropertiesList &other) const; + bool operator!=(const TablePropertiesList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + friend void swap(TablePropertiesList& first, TablePropertiesList& second); + uint16_t length() { + return this->length_; + } + std::list property_list() { + return this->property_list_; + } + void property_list(std::list property_list); + void length(uint16_t length) { + this->length_ = length; + } + void add_property(TableFeatureProp* prop); +}; + +class TableFeatures { +private: + uint16_t length_; + uint8_t table_id_; + std::string name_; + uint64_t metadata_match_; + uint64_t metadata_write_; + uint32_t config_; + uint32_t max_entries_; + TablePropertiesList properties_; +public: + TableFeatures() + : length_(sizeof(struct of13::ofp_table_features)) { + } + TableFeatures(uint8_t table_id, std::string name, uint64_t metadata_match, + uint64_t metadata_write, uint32_t config, uint32_t max_entries); + ~TableFeatures() { + } + bool operator==(const TableFeatures &other) const; + bool operator!=(const TableFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length(); + uint8_t table_id() { + return this->table_id_; + } + std::string name() { + return this->name_; + } + uint64_t metadata_match() { + return this->metadata_match_; + } + uint64_t metadata_write() { + return this->metadata_write_; + } + uint32_t config() { + return this->config_; + } + uint32_t max_entries() { + return this->max_entries_; + } + TablePropertiesList properties() { + return this->properties_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void name(std::string name) { + this->name_ = name; + } + void metadata_match(uint64_t metadata_match) { + this->metadata_match_ = metadata_match; + } + void properties(TablePropertiesList properties); + void add_table_prop(TableFeatureProp* prop); + static TableFeatureProp* make_table_feature_prop(uint16_t type); +}; + +} //End of namespace of13 +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/of13/of13instruction.hh b/include/libfluid-msg/of13/of13instruction.hh new file mode 100644 index 00000000..2ba37385 --- /dev/null +++ b/include/libfluid-msg/of13/of13instruction.hh @@ -0,0 +1,288 @@ +#ifndef OPENFLOW_INSTRUCTION_H +#define OPENFLOW_INSTRUCTION_H + +#include "of13action.hh" +#include "openflow-13.h" +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class Instruction { +protected: + uint16_t type_; + uint16_t length_; +public: + Instruction(); + Instruction(uint16_t type, uint16_t length); + virtual ~Instruction() { + } + virtual bool equals(const Instruction & other); + virtual bool operator==(const Instruction &other) const; + virtual bool operator!=(const Instruction &other) const; + virtual uint16_t set_order() const { + return 0; + } + virtual Instruction* clone() { + return new Instruction(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static Instruction* make_instruction(uint16_t type); +}; + +struct comp_inst_set_order { + bool operator()(Instruction* lhs, Instruction* rhs) const { + return lhs->set_order() < rhs->set_order(); + } +}; + +class InstructionSet { +private: + uint16_t length_; + std::set instruction_set_; +public: + InstructionSet() + : length_(0) { + } + InstructionSet(std::set instruction_set); + InstructionSet(const InstructionSet &other); + InstructionSet& operator=(InstructionSet other); + ~InstructionSet(); + bool operator==(const InstructionSet &other) const; + bool operator!=(const InstructionSet &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + friend void swap(InstructionSet& first, InstructionSet& second); + uint16_t length() { + return this->length_; + } + std::set instruction_set(){ + return this->instruction_set_; + } + void add_instruction(Instruction &inst); + void add_instruction(Instruction *inst); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class GoToTable: public Instruction { +private: + uint8_t table_id_; + const uint16_t set_order_; +public: + GoToTable() + : Instruction(of13::OFPIT_GOTO_TABLE, + sizeof(struct of13::ofp_instruction_goto_table)), + set_order_(60) { + } + GoToTable(uint8_t table_id); + ~GoToTable() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual GoToTable* clone() { + return new GoToTable(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint8_t table_id() { + return this->table_id_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } +}; + +class WriteMetadata: public Instruction { +private: + uint64_t metadata_; + uint64_t metadata_mask_; + const uint16_t set_order_; +public: + WriteMetadata() + : Instruction(of13::OFPIT_WRITE_METADATA, + sizeof(struct of13::ofp_instruction_write_metadata)), + set_order_(50) { + } + WriteMetadata(uint64_t metadata, uint64_t metadata_mask); + ~WriteMetadata() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual WriteMetadata* clone() { + return new WriteMetadata(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t metadata() { + return this->metadata_; + } + uint64_t metadata_mask() { + return this->metadata_mask_; + } + void metadata(uint64_t metadata) { + this->metadata_ = metadata; + } + void metadata_mask(uint64_t metadata_mask) { + this->metadata_mask_ = metadata_mask; + } +}; + +class WriteActions: public Instruction { +private: + ActionSet actions_; + const uint16_t set_order_; +public: + WriteActions() + : Instruction(of13::OFPIT_WRITE_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(40) { + } + WriteActions(ActionSet actions); + ~WriteActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + size_t pack(uint8_t* buffer); + virtual WriteActions* clone() { + return new WriteActions(*this); + } + of_error unpack(uint8_t* buffer); + ActionSet actions() { + return this->actions_; + } + void actions(ActionSet actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class ApplyActions: public Instruction { +private: + ActionList actions_; + const uint16_t set_order_; +public: + ApplyActions() + : Instruction(of13::OFPIT_APPLY_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(20) { + } + ApplyActions(ActionList actions); + ~ApplyActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual ApplyActions* clone() { + return new ApplyActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + ActionList actions() { + return this->actions_; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class ClearActions: public Instruction { +private: + const uint16_t set_order_; +public: + ClearActions() + : Instruction(of13::OFPIT_CLEAR_ACTIONS, + sizeof(struct of13::ofp_instruction)), + set_order_(30) { + } + ~ClearActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual ClearActions* clone() { + return new ClearActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class Meter: public Instruction { +private: + uint32_t meter_id_; + const uint16_t set_order_; +public: + Meter() + : Instruction(of13::OFPIT_METER, + sizeof(struct of13::ofp_instruction_meter)), + set_order_(10) { + } + Meter(uint32_t meter_id); + ~Meter() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual Meter* clone() { + return new Meter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +class InstructionExperimenter: public Instruction { +protected: + uint32_t experimenter_; +public: + InstructionExperimenter() { + } + InstructionExperimenter(uint32_t experimenter); + ~InstructionExperimenter() { + } + virtual bool equals(const Instruction & other); + virtual InstructionExperimenter* clone() { + return new InstructionExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +} + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/of13match.hh b/include/libfluid-msg/of13/of13match.hh new file mode 100644 index 00000000..13b252af --- /dev/null +++ b/include/libfluid-msg/of13/of13match.hh @@ -0,0 +1,1218 @@ +#ifndef OPENFLOW_MATCH_H +#define OPENFLOW_MATCH_H 1 + +#include +#include +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "openflow-13.h" +#include +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class MatchHeader { +protected: + uint16_t type_; + uint16_t length_; +public: + MatchHeader(); + MatchHeader(uint16_t type, uint16_t length); + virtual ~MatchHeader() { + } + bool operator==(const MatchHeader &other) const; + bool operator!=(const MatchHeader &other) const; + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } +}; + +struct oxm_req { + uint16_t eth_type_req[2]; + uint8_t ip_proto_req; + uint8_t icmp_req; +}; + +class OXMTLV { +protected: + uint16_t class__; + uint8_t field_; + bool has_mask_; + uint8_t length_; + struct oxm_req reqs; + void create_oxm_req(uint16_t eth_type1, uint16_t eth_type2, + uint8_t ip_proto, uint8_t icmp); +public: + OXMTLV(); + OXMTLV(uint16_t class_, uint8_t field, bool has_mask, uint8_t length); + virtual ~OXMTLV() { + } + virtual bool equals(const OXMTLV & other); + virtual bool operator==(const OXMTLV &other) const; + virtual bool operator!=(const OXMTLV &other) const; + virtual OXMTLV& operator=(const OXMTLV& field); + virtual OXMTLV* clone() const { + return new OXMTLV(*this); + } + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + uint16_t class_() const { + return this->class__; + } + uint8_t field() const { + return this->field_; + } + bool has_mask() const { + return this->has_mask_; + } + uint8_t length() { + return this->length_; + } + struct oxm_req oxm_reqs() const { + return this->reqs; + } + + void class_(uint16_t class_) { + this->class__ = class_; + } + void field(uint8_t field) { + this->field_ = field; + } + void has_mask(bool has_mask) { + this->has_mask_ = has_mask; + } + void length(uint8_t length) { + this->length_ = length; + } + static uint32_t make_header(uint16_t class_, uint8_t field, bool has_mask, + uint8_t length); + static uint16_t oxm_class(uint32_t header); + static uint8_t oxm_field(uint32_t header); + static bool oxm_has_mask(uint32_t header); + static uint8_t oxm_length(uint32_t header); +}; + +class InPort: public OXMTLV { +private: + uint32_t value_; +public: + InPort(); + InPort(uint32_t value); + ~InPort() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual InPort* clone() const { + return new InPort(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class InPhyPort: public OXMTLV { +private: + uint32_t value_; +public: + InPhyPort(); + InPhyPort(uint32_t value); + ~InPhyPort() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual InPhyPort* clone() const { + return new InPhyPort(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class Metadata: public OXMTLV { +private: + uint64_t value_; + uint64_t mask_; +public: + Metadata(); + Metadata(uint64_t value); + Metadata(uint64_t value, uint64_t mask); + ~Metadata() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual Metadata* clone() const { + return new Metadata(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint64_t value() const { + return this->value_; + } + uint64_t mask() const { + return this->mask_; + } + void value(uint64_t value) { + this->value_ = value; + } + void mask(uint64_t mask) { + this->mask_ = mask; + } +}; + +class EthDst: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + EthDst(); + EthDst(EthAddress value); + EthDst(EthAddress value, EthAddress mask); + ~EthDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthDst* clone() const { + return new EthDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + void mask(EthAddress mask) { + this->mask_ = mask; + } +}; + +class EthSrc: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + EthSrc(); + EthSrc(EthAddress value); + EthSrc(EthAddress value, EthAddress mask); + ~EthSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthSrc* clone() const { + return new EthSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + void mask(EthAddress mask) { + this->mask_ = mask; + } +}; + +class EthType: public OXMTLV { +private: + uint16_t value_; +public: + EthType(); + EthType(uint16_t value); + ~EthType() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthType* clone() const { + return new EthType(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class VLANVid: public OXMTLV { +private: + uint16_t value_; + uint16_t mask_; +public: + VLANVid(); + VLANVid(uint16_t value); + VLANVid(uint16_t value, uint16_t mask); + ~VLANVid() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual VLANVid* clone() const { + return new VLANVid(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + uint16_t mask() const { + return this->mask_; + } + void value(uint16_t value) { + this->value_ = value; + } + void mask(uint16_t mask) { + this->mask_ = mask; + } +}; + +class VLANPcp: public OXMTLV { +private: + uint8_t value_; +public: + VLANPcp(); + VLANPcp(uint8_t value); + ~VLANPcp() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual VLANPcp* clone() const { + return new VLANPcp(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPDSCP: public OXMTLV { +private: + uint8_t value_; +public: + IPDSCP(); + IPDSCP(uint8_t value); + ~IPDSCP() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPDSCP* clone() const { + return new IPDSCP(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPECN: public OXMTLV { +private: + uint8_t value_; +public: + IPECN(); + IPECN(uint8_t value); + ~IPECN() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPECN* clone() const { + return new IPECN(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPProto: public OXMTLV { +private: + uint8_t value_; +public: + IPProto(); + IPProto(uint8_t value); + ~IPProto() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPProto* clone() const { + return new IPProto(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPv4Src: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv4Src(); + IPv4Src(IPAddress value); + IPv4Src(IPAddress value, IPAddress mask); + ~IPv4Src() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv4Src* clone() const { + return new IPv4Src(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class IPv4Dst: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv4Dst(); + IPv4Dst(IPAddress value); + IPv4Dst(IPAddress value, IPAddress mask); + ~IPv4Dst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv4Dst* clone() const { + return new IPv4Dst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class TCPSrc: public OXMTLV { +private: + uint16_t value_; +public: + TCPSrc(); + TCPSrc(uint16_t value); + ~TCPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TCPSrc* clone() const { + return new TCPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } + +}; + +class TCPDst: public OXMTLV { +private: + uint16_t value_; +public: + TCPDst(); + TCPDst(uint16_t value); + ~TCPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TCPDst* clone() const { + return new TCPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class UDPSrc: public OXMTLV { +private: + uint16_t value_; +public: + UDPSrc(); + UDPSrc(uint16_t value); + ~UDPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual UDPSrc* clone() const { + return new UDPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class UDPDst: public OXMTLV { +private: + uint16_t value_; +public: + UDPDst(); + UDPDst(uint16_t value); + ~UDPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual UDPDst* clone() const { + return new UDPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class SCTPSrc: public OXMTLV { +private: + uint16_t value_; +public: + SCTPSrc(); + SCTPSrc(uint16_t value); + ~SCTPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual SCTPSrc* clone() const { + return new SCTPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } + +}; + +class SCTPDst: public OXMTLV { +private: + uint16_t value_; +public: + SCTPDst(); + SCTPDst(uint16_t value); + ~SCTPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual SCTPDst* clone() const { + return new SCTPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class ICMPv4Code: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv4Code(); + ICMPv4Code(uint8_t value); + ~ICMPv4Code() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv4Code* clone() const { + return new ICMPv4Code(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ICMPv4Type: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv4Type(); + ICMPv4Type(uint8_t value); + ~ICMPv4Type() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv4Type* clone() const { + return new ICMPv4Type(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ARPOp: public OXMTLV { +private: + uint16_t value_; +public: + ARPOp(); + ARPOp(uint16_t value); + ~ARPOp() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPOp* clone() const { + return new ARPOp(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class ARPSPA: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + ARPSPA(); + ARPSPA(IPAddress value); + ARPSPA(IPAddress value, IPAddress mask); + ~ARPSPA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPSPA* clone() const { + return new ARPSPA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } + +}; + +class ARPTPA: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + ARPTPA(); + ARPTPA(IPAddress value); + ARPTPA(IPAddress value, IPAddress mask); + ~ARPTPA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPTPA* clone() const { + return new ARPTPA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class ARPSHA: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + ARPSHA(); + ARPSHA(EthAddress value); + ARPSHA(EthAddress value, EthAddress mask); + ~ARPSHA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPSHA* clone() const { + return new ARPSHA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class ARPTHA: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + ARPTHA(); + ARPTHA(EthAddress value); + ARPTHA(EthAddress value, EthAddress mask); + ~ARPTHA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPTHA* clone() const { + return new ARPTHA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + //void value(std::string value); +}; + +class IPv6Src: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv6Src(); + IPv6Src(IPAddress value); + IPv6Src(IPAddress value, IPAddress mask); + ~IPv6Src() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Src* clone() const { + return new IPv6Src(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class IPv6Dst: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv6Dst(); + IPv6Dst(IPAddress value); + IPv6Dst(IPAddress value, IPAddress mask); + ~IPv6Dst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Dst* clone() const { + return new IPv6Dst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class IPV6Flabel: public OXMTLV { +private: + uint32_t value_; + uint32_t mask_; +public: + IPV6Flabel(); + IPV6Flabel(uint32_t value); + IPV6Flabel(uint32_t value, uint32_t mask); + ~IPV6Flabel() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPV6Flabel* clone() const { + return new IPV6Flabel(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + uint32_t mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class ICMPv6Type: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv6Type(); + ICMPv6Type(uint8_t value); + ~ICMPv6Type() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv6Type* clone() const { + return new ICMPv6Type(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ICMPv6Code: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv6Code(); + ICMPv6Code(uint8_t value); + ~ICMPv6Code() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv6Code* clone() const { + return new ICMPv6Code(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPv6NDTarget: public OXMTLV { +private: + IPAddress value_; +public: + IPv6NDTarget(); + IPv6NDTarget(IPAddress value); + ~IPv6NDTarget() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDTarget* clone() const { + return new IPv6NDTarget(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + void value(IPAddress value) { + this->value_ = value; + } +}; + +class IPv6NDSLL: public OXMTLV { +private: + EthAddress value_; +public: + IPv6NDSLL(); + IPv6NDSLL(EthAddress value); + ~IPv6NDSLL() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDSLL* clone() const { + return new IPv6NDSLL(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class IPv6NDTLL: public OXMTLV { +private: + EthAddress value_; +public: + IPv6NDTLL(); + IPv6NDTLL(EthAddress value); + ~IPv6NDTLL() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDTLL* clone() const { + return new IPv6NDTLL(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class MPLSLabel: public OXMTLV { +private: + uint32_t value_; +public: + MPLSLabel(); + MPLSLabel(uint32_t value); + ~MPLSLabel() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSLabel* clone() const { + return new MPLSLabel(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class MPLSTC: public OXMTLV { +private: + uint8_t value_; +public: + MPLSTC(); + MPLSTC(uint8_t value); + ~MPLSTC() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSTC* clone() const { + return new MPLSTC(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class MPLSBOS: public OXMTLV { +private: + uint8_t value_; +public: + MPLSBOS(); + MPLSBOS(uint8_t value); + ~MPLSBOS() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSBOS* clone() const { + return new MPLSBOS(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class PBBIsid: public OXMTLV { +private: + uint32_t value_; + uint32_t mask_; +public: + PBBIsid(); + PBBIsid(uint32_t value); + PBBIsid(uint32_t value, uint32_t mask); + ~PBBIsid() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual PBBIsid* clone() const { + return new PBBIsid(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + uint32_t mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class TUNNELId: public OXMTLV { +private: + uint64_t value_; + uint64_t mask_; +public: + TUNNELId(); + TUNNELId(uint64_t value); + TUNNELId(uint64_t value, uint64_t mask); + ~TUNNELId() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TUNNELId* clone() const { + return new TUNNELId(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint64_t value() const { + return this->value_; + } + void value(uint64_t value) { + this->value_ = value; + } +}; + +class IPv6Exthdr: public OXMTLV { +private: + uint16_t value_; + uint16_t mask_; +public: + IPv6Exthdr(); + IPv6Exthdr(uint16_t value); + IPv6Exthdr(uint16_t value, uint16_t mask); + ~IPv6Exthdr() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Exthdr* clone() const { + return new IPv6Exthdr(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + uint16_t mask() const { + return this->mask_; + } + void value(uint16_t value) { + this->value_ = value; + } + void mask(uint16_t mask) { + this->mask_ = mask; + } +}; + +class Match: public MatchHeader { +private: + /*Current tlvs present by field*/ + std::vector curr_tlvs_; + /*Vector of OXM TLVs*/ + OXMTLV* oxm_tlvs_[OXM_NUM]; +public: + Match(); + Match(const Match &match); + Match& operator=(Match other); + ~Match(); + bool operator==(const Match &other) const; + bool operator!=(const Match &other) const; + static void swap(Match& first, Match& second); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + OXMTLV *oxm_field(uint8_t field); + bool check_pre_req(OXMTLV *tlv); + bool check_dup(OXMTLV *tlv); + void add_oxm_field(OXMTLV &tlv); + void add_oxm_field(OXMTLV* tlv); + uint16_t oxm_fields_len(); + static OXMTLV * make_oxm_tlv(uint8_t field); + InPort* in_port(); + InPhyPort* in_phy_port(); + Metadata* metadata(); + EthSrc* eth_src(); + EthDst* eth_dst(); + EthType* eth_type(); + VLANVid* vlan_vid(); + VLANPcp* vlan_pcp(); + IPDSCP* ip_dscp(); + IPECN* ip_ecn(); + IPProto* ip_proto(); + IPv4Src* ipv4_src(); + IPv4Dst* ipv4_dst(); + TCPSrc* tcp_src(); + TCPDst* tcp_dst(); + UDPSrc* udp_src(); + UDPDst* udp_dst(); + SCTPSrc* sctp_src(); + SCTPDst* sctp_dst(); + ICMPv4Type* icmpv4_type(); + ICMPv4Code* icmpv4_code(); + ARPOp* arp_op(); + ARPSPA* arp_spa(); + ARPTPA* arp_tpa(); + ARPSHA* arp_sha(); + ARPTHA* arp_tha(); + IPv6Src* ipv6_src(); + IPv6Dst* ipv6_dst(); + IPV6Flabel* ipv6_flabel(); + ICMPv6Type* icmpv6_type(); + ICMPv6Code* icmpv6_code(); + IPv6NDTarget* ipv6_nd_target(); + IPv6NDSLL* ipv6_nd_sll(); + IPv6NDTLL* ipv6_nd_tll(); + MPLSLabel* mpls_label(); + MPLSTC* mpls_tc(); + MPLSBOS* mpls_bos(); + PBBIsid* pbb_isid(); + TUNNELId* tunnel_id(); + IPv6Exthdr* ipv6_exthdr(); +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/of13/of13meter.hh b/include/libfluid-msg/of13/of13meter.hh new file mode 100644 index 00000000..7c25843d --- /dev/null +++ b/include/libfluid-msg/of13/of13meter.hh @@ -0,0 +1,315 @@ +#ifndef OPENFLOW_METER_H +#define OPENFLOW_METER_H + +#include +#include "openflow-13.h" +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class MeterBand { +protected: + uint16_t type_; + uint16_t len_; + uint32_t rate_; + uint32_t burst_size_; +public: + MeterBand(); + MeterBand(uint16_t type, uint32_t rate, uint32_t burst_size); + virtual ~MeterBand() { + } + virtual bool equals(const MeterBand & other); + virtual MeterBand* clone() { + return new MeterBand(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t len() { + return this->len_; + } + uint32_t rate() { + return this->rate_; + } + uint32_t burst_size() { + return this->burst_size_; + } + void type(uint16_t type) { + this->type_ = type; + } + void rate(uint32_t rate) { + this->rate_ = rate; + } + void burst_size(uint32_t burst_size) { + this->burst_size_ = burst_size; + } + static bool delete_all(MeterBand * band) { + delete band; + return true; + } + static MeterBand * make_meter_band(uint16_t type); +}; + +class MeterBandList { +private: + uint16_t length_; + std::list band_list_; +public: + MeterBandList() + : length_(0) { + } + MeterBandList(std::list band_list); + MeterBandList(const MeterBandList &other); + MeterBandList& operator=(MeterBandList other); + ~MeterBandList(); + bool operator==(const MeterBandList &other) const; + bool operator!=(const MeterBandList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector meter_bands() const { + return std::vector(band_list_.begin(), band_list_.end()); + } + friend void swap(MeterBandList& first, MeterBandList& second); + uint16_t length() { + return this->length_; + } + void add_band(MeterBand *band); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class MeterBandDrop: public MeterBand { +public: + MeterBandDrop(); + MeterBandDrop(uint32_t rate, uint32_t burst_size); + ~MeterBandDrop() { + } + virtual MeterBandDrop* clone() { + return new MeterBandDrop(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class MeterBandDSCPRemark: public MeterBand { +private: + uint8_t prec_level_; +public: + MeterBandDSCPRemark(); + MeterBandDSCPRemark(uint32_t rate, uint32_t burst_size, uint8_t prec_level); + ~MeterBandDSCPRemark() { + } + virtual bool equals(const MeterBand & other); + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + virtual MeterBandDSCPRemark* clone() { + return new MeterBandDSCPRemark(*this); + } + uint8_t prec_level() { + return this->prec_level_; + } + void prec_level(uint8_t prec_level) { + this->prec_level_ = prec_level; + } +}; + +class MeterBandExperimenter: public MeterBand { +protected: + uint32_t experimenter_; +public: + MeterBandExperimenter(); + MeterBandExperimenter(uint32_t rate, uint32_t burst_size, + uint32_t experimenter); + ~MeterBandExperimenter() { + } + virtual bool equals(const MeterBand & other); + virtual MeterBandExperimenter* clone() { + return new MeterBandExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +class MeterConfig { +private: + uint16_t length_; + uint16_t flags_; + uint32_t meter_id_; + MeterBandList bands_; +public: + MeterConfig(); + MeterConfig(uint16_t flags, uint32_t meter_id); + MeterConfig(uint16_t flags, uint32_t meter_id, MeterBandList bands); + ~MeterConfig() { + } + bool operator==(const MeterConfig &other) const; + bool operator!=(const MeterConfig &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint16_t flags() { + return this->flags_; + } + uint32_t meter_id() { + return this->meter_id_; + } + MeterBandList bands() { + return this->bands_; + } + void bands(MeterBandList bands); + void add_band(MeterBand* band); +}; + +class MeterFeatures { +private: + uint32_t max_meter_; + uint32_t band_types_; + uint32_t capabilities_; + uint8_t max_bands_; + uint8_t max_color_; +public: + MeterFeatures(); + MeterFeatures(uint32_t max_meter, uint32_t band_types, + uint32_t capabilities, uint8_t max_bands, uint8_t max_color); + ~MeterFeatures() { + } + bool operator==(const MeterFeatures &other) const; + bool operator!=(const MeterFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t max_meter() { + return this->max_meter_; + } + uint32_t band_types() { + return this->band_types_; + } + uint32_t capabilities() { + return this->capabilities_; + } + uint8_t max_bands() { + return this->max_bands_; + } + uint8_t max_color() { + return this->max_color_; + } + void max_meter(uint32_t max_meter) { + this->max_meter_ = max_meter; + } + void banc_types(uint32_t band_types) { + this->band_types_ = band_types; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } + void max_bands(uint8_t max_bands) { + this->max_bands_ = max_bands; + } + void max_color(uint8_t max_color) { + this->max_color_ = max_color; + } +}; + +class BandStats { +private: + uint64_t packet_band_count_; + uint64_t byte_band_count_; +public: + BandStats(); + BandStats(uint64_t packet_band_count, uint64_t byte_band_count); + ~BandStats() { + } + bool operator==(const BandStats &other) const; + bool operator!=(const BandStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t packet_band_count() { + return this->packet_band_count_; + } + uint64_t byte_band_count() { + return this->byte_band_count_; + } +}; + +class MeterStats { +private: + uint32_t meter_id_; + uint16_t len_; + uint32_t flow_count_; + uint64_t packet_in_count_; + uint64_t byte_in_count_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + std::vector band_stats_; + +public: + MeterStats(); + MeterStats(uint32_t meter_id, uint32_t flow_count, uint64_t packet_in_count, + uint64_t byte_in_count, uint32_t duration_sec, uint32_t duration_nsec); + MeterStats(uint32_t meter_id, uint32_t flow_count, uint64_t packet_in_count, + uint64_t byte_in_count, uint32_t duration_sec, uint32_t duration_nsec, + std::vector band_stats); + ~MeterStats() { + } + bool operator==(const MeterStats &other) const; + bool operator!=(const MeterStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t meter_id() { + return this->meter_id_; + } + uint16_t len() { + return this->len_; + } + uint64_t packet_in_count() { + return this->packet_in_count_; + } + uint64_t byte_in_count() { + return this->byte_in_count_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + std::vector band_stats() { + return this->band_stats_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } + void packet_in_count(uint64_t packet_in_count) { + this->packet_in_count_ = packet_in_count; + } + void byte_in_count(uint64_t byte_in_count) { + this->byte_in_count_ = byte_in_count; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint64_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void band_stats(std::vector band_stats); + + void add_band_stats(BandStats stats); +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/openflow-13.h b/include/libfluid-msg/of13/openflow-13.h new file mode 100644 index 00000000..b7e315b4 --- /dev/null +++ b/include/libfluid-msg/of13/openflow-13.h @@ -0,0 +1,1718 @@ +#ifndef OPENFLOW_OPENFLOW13_H +#define OPENFLOW_OPENFLOW13_H 1 + +#include "../ofcommon/openflow-common.hh" + +namespace fluid_msg { + +namespace of13 { + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +const uint8_t OFP_VERSION = 0x04; +/* Number of tables in the pipeline */ +#define PIPELINE_TABLES 64 + +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 */ + /* 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 */ + /* Asynchronous messages. */ + 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 */ + /* Barrier messages. */ + 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 */ + /* 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 */ + /* Meters and rate limiters configuration messages. */ + OFPT_METER_MOD = 29, /* Controller/switch message */ +}; + +/* Common header for all Hello Elements */ +struct ofp_hello_elem_header { + uint16_t type; /* One of OFPHET_*. */ + uint16_t length; /* Length in bytes of this element. */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_header) == 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_fluid_header header; + /* Hello element list */ + struct ofp_hello_elem_header elements[0]; +}; +OFP_ASSERT(sizeof(struct ofp_hello) == 8); + +/* Hello elements types. + */ +enum ofp_hello_elem_type { + OFPHET_VERSIONBITMAP = 1, +}; + +/* Version bitmap Hello Element */ +struct ofp_hello_elem_versionbitmap { + uint16_t type; + /* OFPHET_VERSIONBITMAP. */ + uint16_t length; /* Length in bytes of this element. */ + /* 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); + +/******** Common Structures **********************/ + +/* 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 */ +}; +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. */ +}; + +/* 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. */ +}; + +/* Port numbering. Ports are numbered starting from 1. */ +enum ofp_port_no { + /* Maximum number of physical and logical switch ports. */ + OFPP_FLUID_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_FLUID_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_FLUID_CONTROLLER = 0xfffffffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ + OFPP_FLUID_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). */ +}; + +/* 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_PAUSE_ASYM = 1 << 15 /* Asymmetric pause. */ +}; + +/* 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); + +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_FLUID_ALL 0xffffffff + +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff + +enum ofp_queue_properties { + OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ + OFPQT_MAX_RATE = 2, /* Maximum datarate. */ + OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ +}; + +/* 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_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 */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); + +/* 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); + +const uint8_t OFP_OXM_HEADER_LEN = 4; +const uint8_t OFP_OXM_IN_PORT_LEN = 4; +const uint8_t OFP_OXM_IN_PHY_PORT_LEN = 4; +const uint8_t OFP_OXM_METADATA_LEN = 8; +const uint8_t OFP_OXM_ETH_TYPE_LEN = 2; +const uint8_t OFP_OXM_VLAN_VID_LEN = 2; +const uint8_t OFP_OXM_VLAN_PCP_LEN = 1; +const uint8_t OFP_OXM_IP_DSCP_LEN = 1; +const uint8_t OFP_OXM_IP_ECN_LEN = 1; +const uint8_t OFP_OXM_IP_PROTO_LEN = 1; +const uint8_t OFP_OXM_IPV4_LEN = 4; +const uint8_t OFP_OXM_TP_LEN = 2; +const uint8_t OFP_OXM_ARP_OP_LEN = 2; +const uint8_t OFP_OXM_ICMP_TYPE_LEN = 1; +const uint8_t OFP_OXM_ICMP_CODE_LEN = 1; +const uint8_t OFP_OXM_IPV6_LEN = 16; +const uint8_t OFP_OXM_IPV6_FLABEL_LEN = 4; +const uint8_t OFP_OXM_MPLS_TC_LEN = 1; +const uint8_t OFP_OXM_MPLS_LABEL_LEN = 4; +const uint8_t OFP_OXM_MPLS_BOS_LEN = 1; +const uint8_t OFP_OXM_IPV6_PBB_ISID_LEN = 4; +const uint8_t OFP_OXM_TUNNEL_ID_LEN = 8; +const uint8_t OFP_OXM_IPV6_EXTHDR_LEN = 2; + +/* 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 */ +}; +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 */ +}; + +/* 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. + */ +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 */ +}; + +#define OXM_NUM 40 + +/* 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_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 */ +}; + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * 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. */ +}; + +/* 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. */ +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. */ +}; +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 */ +}; + +enum ofp_action_type { + 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_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_EXPERIMENTER = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out ’port’. + * When the ’port’ is the OFPP_FLUID_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_output) == 16); + +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. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); + +/* 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]; +}; +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]; +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_action_pop_mpls) == 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 */ +}; +OFP_ASSERT(sizeof(struct ofp_action_set_field) == 8); + +/* Action header for OFPAT_EXPERIMENTER. + * 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_experimenter_header) == 8); + +/* 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); + +/* 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); + +/* Instruction structure for experimental instructions */ +struct ofp_instruction_experimenter { + uint16_t type; /* OFPIT_EXPERIMENTER */ + uint16_t len; /* Length of this struct in bytes */ + /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint32_t experimenter; + /* Experimenter-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_instruction_experimenter) == 8); + +/*************Controller-to-Switch Messages******************/ + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_fluid_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; +}; +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. */ +}; + +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 */ +}; + +/* 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. */ +}; + +/* Configure/Modify behavior of a flow table */ +struct ofp_table_mod { + struct ofp_fluid_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); + +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 +}; + +#define OFP_FLUID_DEFAULT_PRIORITY 0x8000 +#define OFP_FLUID_FLOW_PERMANENT 0 + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_fluid_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_FLUID_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); + +enum ofp_flow_mod_command { + 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_STRICT = 4, /* Delete entry strictly matching wildcards and + priority. */ +}; + +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. */ +}; + +/* Group numbering. Groups can use any number up to OFPG_MAX. */ +enum ofp_group { + /* Last usable group number. */ + OFPG_MAX = 0xffffff00, + + /* 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).*/ +}; + +/* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_bucket) == 16); + +/* Group setup and teardown (controller -> datapath). */ +struct ofp_group_mod { + struct ofp_fluid_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. */ +enum ofp_group_type { + OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ + OFPGT_SELECT = 1, /* Select group. */ + OFPGT_INDIRECT = 2, /* Indirect group. */ + OFPGT_FF = 3, /* Fast failover group. */ +}; + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_fluid_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); + +/* 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); + +/* Meter configuration. OFPT_METER_MOD. */ +struct ofp_meter_mod { + struct ofp_fluid_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); + +/* 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. */ +}; + +/* 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 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 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]; +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_dscp_remark) == 16); + +/* OFPMBT_EXPERIMENTER band - Write actions in action set */ +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. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_experimenter) == 16); + +struct ofp_multipart_request { + struct ofp_fluid_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_ASSERT(sizeof(struct ofp_multipart_request) == 16); + +enum ofp_multipart_request_flags { + OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ +}; + +enum ofp_multipart_reply_flags { + OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_multipart_reply { + struct ofp_fluid_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); + +enum ofp_multipart_types { + /* Description of this OpenFlow switch. + * 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. */ + OFPMP_FLOW = 1, + /* Aggregate flow statistics. + * 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. */ + 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. */ + 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 */ + 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. */ + OFPMP_GROUP = 6, + /* Group description statistics. + * The request body is empty. + * The reply body is an array of struct ofp_group_desc_stats. */ + OFPMP_GROUP_DESC = 7, + /* Group features. + * The request body is empty. + * The reply body is struct ofp_group_features_stats. */ + 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. */ + OFPMP_METER_CONFIG = 10, + /* 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. */ + OFPMP_TABLE_FEATURES = 12, + /* Port description. + * 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. */ + OFPMP_EXPERIMENTER = 0xffff +}; + +/* 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_FLUID_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. */ + uint16_t 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. */ + //struct ofp_instruction instructions[0]; /* Instruction set. */ +}; +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_FLUID_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. */ +}; +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_FLUID_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. + */ +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. */ +}; + +/* 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. */ + /* 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 */ +}; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_instructions) == 4); + +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. */ + /* 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]; +}; +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. */ + /* 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 */ +}; +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. */ + /* 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 */ +}; +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_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_FLUID_ANY). */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 112); + +struct ofp_queue_stats_request { + uint32_t port_no; /* All ports if OFPP_FLUID_ANY. */ + uint32_t queue_id; /* All queues if OFPQ_FLUID_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_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 + duration_sec. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); + +/* 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. */ +}; +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. */ +}; +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 + duration_sec. */ + struct ofp_bucket_counter bucket_stats[0]; + +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_group_desc_stats) == 8); + +/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ +struct ofp_group_features { + 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) == 40); + +/* 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 */ +}; + +/* 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. */ +}; +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. */ +}; +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. */ + struct ofp_meter_band_stats band_stats[0]; /* The band_stats length is + 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. */ + struct ofp_meter_band_header bands[0]; /* The bands length is + 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]; +}; +OFP_ASSERT(sizeof(struct ofp_meter_features) == 16); + +/* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */ +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_experimenter_multipart_header) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_fluid_header header; + uint32_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_FLUID_MAX), + or OFPP_FLUID_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_fluid_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_fluid_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_FLUID_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.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 24); + +#define OFP_NO_BUFFER 0xffffffff + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_fluid_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 */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); + +/* 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 */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_fluid_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); + +/* 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. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_fluid_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_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. */ +}; + +/* 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_fluid_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_fluid_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_fluid_header.version not supported. */ + OFPBRC_BAD_TYPE = 1, /* ofp_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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. */ +}; + +/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ +struct ofp_error_experimenter_msg { + struct ofp_fluid_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_error_experimenter_msg) == 16); + +/* Experimenter extension. */ +struct ofp_experimenter_header { + struct ofp_fluid_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); + +} + +} //End of namespace fluid_msg + +#endif /* openflow/openflow.h */ diff --git a/include/libfluid-msg/of13msg.hh b/include/libfluid-msg/of13msg.hh new file mode 100644 index 00000000..b56f8acd --- /dev/null +++ b/include/libfluid-msg/of13msg.hh @@ -0,0 +1,1581 @@ +#ifndef OF13MSG_H +#define OF13MSG_H 1 + +#include "ofcommon/msg.hh" +#include "of13/of13common.hh" +#include "of13/of13action.hh" +#include "of13/of13meter.hh" + +namespace fluid_msg { + +/** + Base class for OpenFlow 1.3 Role messages. + */ +class RoleCommon: public OFMsg { +private: + uint32_t role_; + uint64_t generation_id_; +public: + RoleCommon(uint8_t version, uint8_t type); + RoleCommon(uint8_t version, uint8_t type, uint32_t xid, uint32_t role, + uint64_t generation_id); + virtual ~RoleCommon() { + } + bool operator==(const RoleCommon &other) const; + bool operator!=(const RoleCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t role() { + return this->role_; + } + uint64_t generation_id() { + return this->generation_id_; + } + void role(uint32_t role) { + this->role_ = role; + } + void generation_id(uint64_t generation_id) { + this->generation_id_ = generation_id; + } +}; + +/** + Base class for OpenFlow 1.3 Async Config messages. + */ +class AsyncConfigCommon: public OFMsg { +protected: + std::vector packet_in_mask_; + std::vector port_status_mask_; + std::vector flow_removed_mask_; +public: + AsyncConfigCommon(uint8_t version, uint8_t type); + AsyncConfigCommon(uint8_t version, uint8_t type, uint32_t xid); + AsyncConfigCommon(uint8_t version, uint8_t type, uint32_t xid, + std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + virtual ~AsyncConfigCommon() { + } + bool operator==(const AsyncConfigCommon &other) const; + bool operator!=(const AsyncConfigCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + /*TODO check for specific message type */ + uint32_t master_equal_packet_in_mask() { + return this->packet_in_mask_[0]; + } + uint32_t master_equal_port_status_mask() { + return this->port_status_mask_[0]; + } + uint32_t master_equal_flow_removed_mask() { + return this->port_status_mask_[0]; + } + uint32_t slave_packet_in_mask() { + return this->packet_in_mask_[1]; + } + uint32_t slave_port_status_mask() { + return this->port_status_mask_[1]; + } + uint32_t slave_flow_removed_mask() { + return this->port_status_mask_[1]; + } + void master_equal_packet_in_mask(uint32_t mask) { + this->packet_in_mask_[0] = mask; + } + void master_equal_port_status_mask(uint32_t mask) { + this->port_status_mask_[0] = mask; + } + void master_equal_flow_removed_mask(uint32_t mask) { + this->port_status_mask_[0] = mask; + } + void slave_packet_in_mask(uint32_t mask) { + this->packet_in_mask_[1] = mask; + } + void slave_port_status_mask(uint32_t mask) { + this->port_status_mask_[1] = mask; + } + void slave_flow_removed_mask(uint32_t mask) { + this->port_status_mask_[1] = mask; + } +}; + +/** + Classes for creating and parsing OpenFlow 1.3 messages. + */ +namespace of13 { + +/** + OpenFlow 1.3 OFPT_HELLO message + */ +class Hello: public OFMsg { +private: + std::list elements_; +public: + Hello(); + Hello(uint32_t xid); + Hello(uint32_t xid, std::list elements); + ~Hello() { + } + bool operator==(const Hello &other) const; + bool operator!=(const Hello &other) const; + uint8_t* pack(); + of_error unpack(uint8_t* buffer); + std::list elements() { + return this->elements_; + } + void elements(std::list elements); + void add_element(HelloElemVersionBitmap element); + uint32_t elements_len(); +}; + +/** + OpenFlow 1.3 OFPT_ERROR message. + */ +class Error: public ErrorCommon { +public: + Error(); + Error(uint32_t xid, uint16_t err_type, uint16_t code); + Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len); + ~Error() { + } +}; + +/** + OpenFlow 1.3 OFPT_ECHO_REQUEST message. + */ +class EchoRequest: public EchoCommon { +public: + EchoRequest(); + EchoRequest(uint32_t xid); + ~EchoRequest() { + } +}; + +/** + OpenFlow 1.3 OFPT_ECHO_REPLY message. + */ +class EchoReply: public EchoCommon { +public: + EchoReply(); + EchoReply(uint32_t xid); + ~EchoReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_EXPERIMENTER message. + Experimenter messages should inherit from this class. + */ +class Experimenter: public OFMsg { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + Experimenter(); + Experimenter(uint32_t xid, uint32_t experimenter, uint32_t exp_type); + virtual ~Experimenter() { + } + bool operator==(const Experimenter &other) const; + bool operator!=(const Experimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPT_FEATURES_REQUEST message. + */ +class FeaturesRequest: public OFMsg { +public: + FeaturesRequest(); + FeaturesRequest(uint32_t xid); + ~FeaturesRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_FEATURES_REPLY message. + */ +class FeaturesReply: public FeaturesReplyCommon { + uint8_t auxiliary_id_; +public: + FeaturesReply(); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint8_t auxiliary_id, uint32_t capabilities); + ~FeaturesReply() { + } + bool operator==(const FeaturesReply &other) const; + bool operator!=(const FeaturesReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t auxiliary_id() { + return this->auxiliary_id_; + } + void auxiliary_id(uint8_t auxiliary_id) { + this->auxiliary_id_ = auxiliary_id; + } +}; + +/** + OpenFlow 1.3 OFPT_GET_CONFIG_REQUEST message. + */ +class GetConfigRequest: public OFMsg { +public: + GetConfigRequest(); + GetConfigRequest(uint32_t xid); + ~GetConfigRequest() { + } + ; + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_GET_CONFIG_REPLY message. + */ +class GetConfigReply: public SwitchConfigCommon { +public: + GetConfigReply(); + GetConfigReply(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~GetConfigReply() { + } + ; +}; + +/** + OpenFlow 1.3 OFPT_SET_CONFIG_REPLY message. + */ +class SetConfig: public SwitchConfigCommon { +public: + SetConfig(); + SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~SetConfig() { + } + ; +}; + +/** + OpenFlow 1.3 OFPT_PACKET_OUT message. + */ +class PacketOut: public PacketOutCommon { +private: + uint32_t in_port_; +public: + PacketOut(); + PacketOut(uint32_t xid, uint32_t buffer_id, uint32_t in_port); + bool operator==(const PacketOut &other) const; + bool operator!=(const PacketOut &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t in_port() { + return this->in_port_; + } + void in_port(uint32_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.3 OFPT_PACKET_IN message. + */ +class PacketIn: public PacketInCommon { +private: + uint8_t table_id_; + uint64_t cookie_; + of13::Match match_; +public: + PacketIn(); + PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t total_len, + uint8_t reason, uint8_t table_id, uint64_t cookie); + ~PacketIn() { + } + ; + virtual uint16_t length(); + bool operator==(const PacketIn &other) const; + bool operator!=(const PacketIn &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() const { + return this->table_id_; + } + uint64_t cookie() const { + return this->cookie_; + } + of13::Match& match() { + return this->match_; + } + const of13::Match& match() const { + return this->match_; + } + ; + OXMTLV * get_oxm_field(uint8_t field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); +}; + +/** + OpenFlow 1.3 OFPT_FLOW_MOD message. + */ +class FlowMod: public FlowModCommon { +private: + uint8_t command_; + uint64_t cookie_mask_; + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + of13::Match match_; + InstructionSet instructions_; +public: + FlowMod(); + FlowMod(uint32_t xid, uint64_t cookie, uint64_t cookie_mask, + uint8_t table_id, uint8_t command, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint32_t out_port, uint32_t out_group, uint16_t flags); + ~FlowMod() { + } + bool operator==(const FlowMod &other) const; + bool operator!=(const FlowMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + virtual uint16_t length(); + uint8_t command(){ + return this->command_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + of13::Match match() { + return this->match_; + } + of13::InstructionSet instructions() { + return this->instructions_; + } + OXMTLV * get_oxm_field(uint8_t field); + void command(uint8_t command){ + this->command_ = command; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); + void instructions(InstructionSet instructions); + void add_instruction(Instruction &inst); + void add_instruction(Instruction* inst); +}; + +/** + OpenFlow 1.3 OFPT_FLOW_REMOVED message. + */ +class FlowRemoved: public FlowRemovedCommon { +private: + uint8_t table_id_; + uint16_t hard_timeout_; + of13::Match match_; +public: + FlowRemoved(); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count, of13::Match); + ~FlowRemoved() { + } + virtual uint16_t length(); + bool operator==(const FlowRemoved &other) const; + bool operator!=(const FlowRemoved &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() { + return this->table_id_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + of13::Match match() { + return this->match_; + } + void match(of13::Match match) { + this->match_ = match; + } +}; + +/** + OpenFlow 1.3 OFPT_PORT_STATUS message. + */ +class PortStatus: public PortStatusCommon { +private: + of13::Port desc_; +public: + PortStatus(); + PortStatus(uint32_t xid, uint8_t reason, of13::Port desc); + ~PortStatus() { + } + bool operator==(const PortStatus &other) const; + bool operator!=(const PortStatus &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Port desc() { + return this->desc_; + } + void desc(of13::Port desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.3 OFPT_PORT_MOD message. + */ +class PortMod: public PortModCommon { +private: + uint32_t port_no_; +public: + PortMod(); + PortMod(uint32_t xid, uint32_t port_no, EthAddress hw_addr, uint32_t config, + uint32_t mask, uint32_t advertise); + ~PortMod() { + } + bool operator==(const PortMod &other) const; + bool operator!=(const PortMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port_no() { + return this->port_no_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.3 OFPT_GROUP_MOD message. + */ +class GroupMod: public OFMsg { +private: + uint16_t command_; + uint8_t group_type_; + uint32_t group_id_; + std::vector buckets_; +public: + GroupMod(); + GroupMod(uint32_t xid, uint16_t command, uint8_t type, uint32_t group_id); + GroupMod(uint32_t xid, uint16_t command, uint8_t type, uint32_t group_id, + std::vector buckets); + ~GroupMod() { + } + bool operator==(const GroupMod &other) const; + bool operator!=(const GroupMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command() { + return this->command_; + } + uint8_t type() { + return this->type_; + } + uint32_t group_id() { + return this->group_id_; + } + std::vector buckets() { + return this->buckets_; + } + void commmand(uint16_t command) { + this->command_ = command; + } + void group_type(uint8_t type) { + this->group_type_ = type; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void buckets(std::vector buckets); + void add_bucket(Bucket bucket); + size_t buckets_len(); +}; + +/** + OpenFlow 1.3 OFPT_TABLE_MOD message. + */ +class TableMod: public OFMsg { +private: + uint8_t table_id_; + uint32_t config_; +public: + TableMod(); + TableMod(uint32_t xid, uint8_t table_id, uint32_t config); + ~TableMod() { + } + bool operator==(const TableMod &other) const; + bool operator!=(const TableMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() { + return this->table_id_; + } + uint32_t config() { + return this->config_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void config(uint32_t config) { + this->config_ = config; + } +}; + +/** + OpenFlow 1.3 OFPT_MULTIPART_REQUEST message header. Multipart request + messages should inherit from this class. + */ +class MultipartRequest: public OFMsg { +protected: + uint16_t mpart_type_; + uint16_t flags_; +public: + MultipartRequest(); + MultipartRequest(uint16_t type); + MultipartRequest(uint32_t xid, uint16_t type, uint16_t flags); + virtual ~MultipartRequest() { + } + bool operator==(const MultipartRequest &other) const; + bool operator!=(const MultipartRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t mpart_type() { + return this->mpart_type_; + } + uint16_t flags() { + return this->flags_; + } + void type(uint16_t type) { + this->mpart_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.3 OFPT_MULTIPART_REPLY message header. Multipart reply + messages should inherit from this class. + */ +class MultipartReply: public OFMsg { +protected: + uint16_t mpart_type_; + uint16_t flags_; +public: + MultipartReply(); + MultipartReply(uint16_t type); + MultipartReply(uint32_t xid, uint16_t type, uint16_t flags); + virtual ~MultipartReply() { + } + bool operator==(const MultipartReply &other) const; + bool operator!=(const MultipartReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t mpart_type() { + return this->mpart_type_; + } + uint16_t flags() { + return this->flags_; + } + void type(uint16_t type) { + this->mpart_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.3 OFPMP_DESC multipart request. + */ +class MultipartRequestDesc: public MultipartRequest { +public: + MultipartRequestDesc(); + MultipartRequestDesc(uint32_t xid, uint16_t flags); + ~MultipartRequestDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_DESC multipart reply. + */ +class MultipartReplyDesc: public MultipartReply { +private: + SwitchDesc desc_; +public: + MultipartReplyDesc(); + MultipartReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc); + MultipartReplyDesc(uint32_t xid, uint16_t flags, std::string mfr_desc, + std::string hw_desc, std::string sw_desc, std::string serial_num, + std::string dp_desc); + ~MultipartReplyDesc() { + } + bool operator==(const MultipartReplyDesc &other) const; + bool operator!=(const MultipartReplyDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + SwitchDesc desc() { + return this->desc_; + } + void set_desc(SwitchDesc desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.3 OFPMP_FLOW multipart request. + */ +class MultipartRequestFlow: public MultipartRequest { +private: + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + uint64_t cookie_; + uint64_t cookie_mask_; + of13::Match match_; +public: + MultipartRequestFlow(); + MultipartRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask); + MultipartRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match); + ~MultipartRequestFlow() { + } + bool operator==(const MultipartRequestFlow &other) const; + bool operator!=(const MultipartRequestFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV* field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } +}; + +/** + OpenFlow 1.3 OFPMP_FLOW multipart reply. + */ +class MultipartReplyFlow: public MultipartReply { +private: + std::vector flow_stats_; +public: + MultipartReplyFlow(); + MultipartReplyFlow(uint32_t xid, uint16_t flags); + MultipartReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats); + ~MultipartReplyFlow() { + } + bool operator==(const MultipartReplyFlow &other) const; + bool operator!=(const MultipartReplyFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector flow_stats() { + return this->flow_stats_; + } + void flow_stats(std::vector flow_stats); + void add_flow_stats(of13::FlowStats); +}; + +/** + OpenFlow 1.3 OFPMP_AGGREGATE multipart request. + */ +class MultipartRequestAggregate: public MultipartRequest { +private: + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + uint64_t cookie_; + uint64_t cookie_mask_; + of13::Match match_; +public: + MultipartRequestAggregate(); + MultipartRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask); + MultipartRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match); + ~MultipartRequestAggregate() { + } + virtual uint16_t length(); + bool operator==(const MultipartRequestAggregate &other) const; + bool operator!=(const MultipartRequestAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } +}; + +/** + OpenFlow 1.3 OFPMP_AGGREGATE multipart reply. + */ +class MultipartReplyAggregate: public MultipartReply { +private: + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t flow_count_; +public: + MultipartReplyAggregate(); + MultipartReplyAggregate(uint32_t xid, uint16_t flags, uint64_t packet_count, + uint64_t byte_count, uint32_t flow_count); + ~MultipartReplyAggregate() { + } + bool operator==(const MultipartReplyAggregate &other) const; + bool operator!=(const MultipartReplyAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t flow_count() { + return this->flow_count_; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void flow_count(uint32_t flow_count) { + this->flow_count_ = flow_count; + } +}; + +/** + OpenFlow 1.3 OFPMP_TABLE multipart request. + */ +class MultipartRequestTable: public MultipartRequest { +public: + MultipartRequestTable(); + MultipartRequestTable(uint32_t xid, uint16_t flags); + ~MultipartRequestTable() { + } + ; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_TABLE multipart reply. + */ +class MultipartReplyTable: public MultipartReply { +private: + std::vector table_stats_; +public: + MultipartReplyTable(); + MultipartReplyTable(uint32_t xid, uint16_t flags); + MultipartReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats); + ~MultipartReplyTable() { + } + bool operator==(const MultipartReplyTable &other) const; + bool operator!=(const MultipartReplyTable &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_stats() { + return this->table_stats_; + } + void table_stats(std::vector table_stats); + void add_table_stat(of13::TableStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_STATS multipart request. + */ +class MultipartRequestPortStats: public MultipartRequest { +private: + uint32_t port_no_; +public: + MultipartRequestPortStats(); + MultipartRequestPortStats(uint32_t xid, uint16_t flags, uint32_t port_no); + ~MultipartRequestPortStats() { + } + bool operator==(const MultipartRequestPortStats &other) const; + bool operator!=(const MultipartRequestPortStats &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port_no() { + return this->port_no_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.3 OFPMP_PORT_STATS multipart reply. + */ +class MultipartReplyPortStats: public MultipartReply { +private: + std::vector port_stats_; +public: + MultipartReplyPortStats(); + MultipartReplyPortStats(uint32_t xid, uint16_t flags); + MultipartReplyPortStats(uint32_t xid, uint16_t flags, + std::vector port_stats); + ~MultipartReplyPortStats() { + } + bool operator==(const MultipartReplyPortStats &other) const; + bool operator!=(const MultipartReplyPortStats &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector port_stats() { + return this->port_stats_; + } + void port_stats(std::vector port_stats); + void add_port_stat(of13::PortStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_QUEUE multipart request. + */ +class MultipartRequestQueue: public MultipartRequest { +private: + uint32_t port_no_; + uint32_t queue_id_; +public: + MultipartRequestQueue(); + MultipartRequestQueue(uint32_t xid, uint16_t flags, uint32_t port_no, + uint32_t queue_id); + ~MultipartRequestQueue() { + } + bool operator==(const MultipartRequestQueue &other) const; + bool operator!=(const MultipartRequestQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_QUEUE multipart reply. + */ +class MultipartReplyQueue: public MultipartReply { +private: + std::vector queue_stats_; +public: + MultipartReplyQueue(); + MultipartReplyQueue(uint32_t xid, uint16_t flags); + MultipartReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats); + ~MultipartReplyQueue() { + } + bool operator==(const MultipartReplyQueue &other) const; + bool operator!=(const MultipartReplyQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->queue_stats_; + } + void queue_stats(std::vector queue_stats_); + void add_queue_stat(of13::QueueStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP multipart request. + */ +class MultipartRequestGroup: public MultipartRequest { +private: + uint32_t group_id_; +public: + MultipartRequestGroup(); + MultipartRequestGroup(uint32_t xid, uint16_t flags, uint32_t group_id); + ~MultipartRequestGroup() { + } + bool operator==(const MultipartRequestGroup &other) const; + bool operator!=(const MultipartRequestGroup &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t group_id() { + return this->group_id_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_GROUP multipart reply. + */ +class MultipartReplyGroup: public MultipartReply { +private: + std::vector group_stats_; +public: + MultipartReplyGroup(); + MultipartReplyGroup(uint32_t xid, uint16_t flags); + MultipartReplyGroup(uint32_t xid, uint16_t flags, + std::vector group_stats); + ~MultipartReplyGroup() { + } + bool operator==(const MultipartReplyGroup &other) const; + bool operator!=(const MultipartReplyGroup &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->group_stats_; + } + void group_stats(std::vector group_stats); + void add_group_stats(of13::GroupStats stat); + size_t group_stats_len(); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_DESC multipart request. + */ +class MultipartRequestGroupDesc: public MultipartRequest { +public: + MultipartRequestGroupDesc(); + MultipartRequestGroupDesc(uint32_t xid, uint16_t flags); + ~MultipartRequestGroupDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_DESC multipart reply. + */ +class MultipartReplyGroupDesc: public MultipartReply { +private: + std::vector group_desc_; +public: + MultipartReplyGroupDesc(); + MultipartReplyGroupDesc(uint32_t xid, uint16_t flags); + MultipartReplyGroupDesc(uint32_t xid, uint16_t flags, + std::vector group_desc); + ~MultipartReplyGroupDesc() { + } + bool operator==(const MultipartReplyGroupDesc &other) const; + bool operator!=(const MultipartReplyGroupDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->group_desc_; + } + void group_desc(std::vector group_desc); + void add_group_desc(of13::GroupDesc stat); + size_t desc_len(); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_FEATURES multipart request. + */ +class MultipartRequestGroupFeatures: public MultipartRequest { +public: + MultipartRequestGroupFeatures(); + MultipartRequestGroupFeatures(uint32_t xid, uint16_t flags); + ~MultipartRequestGroupFeatures() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_FEATURES multipart reply. + */ +class MultipartReplyGroupFeatures: public MultipartReply { +private: + of13::GroupFeatures features_; +public: + MultipartReplyGroupFeatures(); + MultipartReplyGroupFeatures(uint32_t xid, uint16_t flags, + of13::GroupFeatures features); + ~MultipartReplyGroupFeatures() { + } + bool operator==(const MultipartReplyGroupFeatures &other) const; + bool operator!=(const MultipartReplyGroupFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::GroupFeatures features() { + return this->features_; + } + void features(of13::GroupFeatures features) { + this->features_ = features; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER multipart request. + */ +class MultipartRequestMeter: public MultipartRequest { +private: + uint32_t meter_id_; +public: + MultipartRequestMeter(); + MultipartRequestMeter(uint32_t xid, uint16_t flags, uint32_t meter_id); + bool operator==(const MultipartRequestMeter &other) const; + bool operator!=(const MultipartRequestMeter &other) const; + ~MultipartRequestMeter() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER multipart reply. + */ +class MultipartReplyMeter: public MultipartReply { +private: + std::vector meter_stats_; +public: + MultipartReplyMeter(); + MultipartReplyMeter(uint32_t xid, uint16_t flags); + MultipartReplyMeter(uint32_t xid, uint16_t flags, + std::vector meter_stats); + ~MultipartReplyMeter() { + } + bool operator==(const MultipartReplyMeter &other) const; + bool operator!=(const MultipartReplyMeter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector meter_stats() { + return this->meter_stats_; + } + void meter_stats(std::vector meter_stats); + void add_meter_stats(MeterStats stats); + size_t meter_stats_len(); +}; + +/** + OpenFlow 1.3 OFPMP_METER_CONFIG multipart request. + */ +class MultipartRequestMeterConfig: public MultipartRequest { +private: + uint32_t meter_id_; +public: + MultipartRequestMeterConfig(); + MultipartRequestMeterConfig(uint32_t xid, uint16_t flags, uint32_t meter_id); + bool operator==(const MultipartRequestMeterConfig &other) const; + bool operator!=(const MultipartRequestMeterConfig &other) const; + ~MultipartRequestMeterConfig() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER_CONFIG multipart reply. + */ +class MultipartReplyMeterConfig: public MultipartReply { + std::vector meter_config_; +public: + MultipartReplyMeterConfig(); + MultipartReplyMeterConfig(uint32_t xid, uint16_t flags); + MultipartReplyMeterConfig(uint32_t xid, uint16_t flags, + std::vector meter_config); + ~MultipartReplyMeterConfig() { + } + bool operator==(const MultipartReplyMeterConfig &other) const; + bool operator!=(const MultipartReplyMeterConfig &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector meter_config() { + return this->meter_config_; + } + void meter_config(std::vector meter_config); + void add_meter_config(MeterConfig config); + size_t meter_config_len(); +}; + +/** + OpenFlow 1.3 OFPMP_METER_FEATURES multipart request. + */ +class MultipartRequestMeterFeatures: public MultipartRequest { +public: + MultipartRequestMeterFeatures(); + MultipartRequestMeterFeatures(uint32_t xid, uint16_t flags); + ~MultipartRequestMeterFeatures() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_METER_FEATURES multipart reply. + */ +class MultipartReplyMeterFeatures: public MultipartReply { +private: + MeterFeatures meter_features_; +public: + MultipartReplyMeterFeatures(); + MultipartReplyMeterFeatures(uint32_t xid, uint16_t flags, + MeterFeatures features); + ~MultipartReplyMeterFeatures() { + } + bool operator==(const MultipartReplyMeterFeatures &other) const; + bool operator!=(const MultipartReplyMeterFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + MeterFeatures meter_features() { + return this->meter_features_; + } + void meter_features(MeterFeatures meter_features) { + this->meter_features_ = meter_features; + } +}; + +/** + OpenFlow 1.3 OFPMP_TABLE_FEATURES multipart request. + */ +class MultipartRequestTableFeatures: public MultipartRequest { +private: + std::vector tables_features_; +public: + MultipartRequestTableFeatures(); + MultipartRequestTableFeatures(uint32_t xid, uint16_t flags); + MultipartRequestTableFeatures(uint32_t xid, uint16_t flags, + std::vector table_features); + ~MultipartRequestTableFeatures() { + } + bool operator==(const MultipartRequestTableFeatures &other) const; + bool operator!=(const MultipartRequestTableFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector tables_features() { + return this->tables_features_; + } + void tables_features(std::vector tables_features); + void add_table_features(TableFeatures table_feature); +}; + +/** + OpenFlow 1.3 OFPMP_TABLE_FEATURES multipart reply. + */ +class MultipartReplyTableFeatures: public MultipartReply { +private: + std::vector tables_features_; +public: + MultipartReplyTableFeatures(); + MultipartReplyTableFeatures(uint32_t xid, uint16_t flags); + MultipartReplyTableFeatures(uint32_t xid, uint16_t flags, + std::vector table_features); + ~MultipartReplyTableFeatures() { + } + bool operator==(const MultipartReplyTableFeatures &other) const; + bool operator!=(const MultipartReplyTableFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_features() { + return this->tables_features_; + } + void tables_features(std::vector tables_features); + void add_table_features(TableFeatures table_feature); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_DESC multipart request. + */ +class MultipartRequestPortDescription: public MultipartRequest { +public: + MultipartRequestPortDescription(); + MultipartRequestPortDescription(uint32_t xid, uint16_t flags); + ~MultipartRequestPortDescription() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_DESC multipart reply. + */ +class MultipartReplyPortDescription: public MultipartReply { +private: + std::vector ports_; +public: + MultipartReplyPortDescription(); + MultipartReplyPortDescription(uint32_t xid, uint16_t flags); + MultipartReplyPortDescription(uint32_t xid, uint16_t flags, + std::vector ports); + ~MultipartReplyPortDescription() { + } + bool operator==(const MultipartReplyPortDescription &other) const; + bool operator!=(const MultipartReplyPortDescription &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector ports() { + return this->ports_; + } + void ports(std::vector ports); + void add_port(of13::Port); +}; + +/** + OpenFlow 1.3 OFPMP_EXPERIMENTER multipart request. + Multipart request experimenter messages should inherit from this class. + */ +class MultipartRequestExperimenter: public MultipartRequest { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + MultipartRequestExperimenter(); + MultipartRequestExperimenter(uint32_t xid, uint16_t flags, + uint32_t experimenter, uint32_t exp_type); + virtual ~MultipartRequestExperimenter() { + } + bool operator==(const MultipartRequestExperimenter &other) const; + bool operator!=(const MultipartRequestExperimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPMP_EXPERIMENTER multipart reply. + Multipart reply experimenter messages should inherit from this class. + */ +class MultipartReplyExperimenter: public MultipartReply { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + MultipartReplyExperimenter(); + MultipartReplyExperimenter(uint32_t xid, uint16_t flags, + uint32_t experimenter, uint32_t exp_type); + virtual ~MultipartReplyExperimenter() { + } + bool operator==(const MultipartReplyExperimenter &other) const; + bool operator!=(const MultipartReplyExperimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPT_BARRIER_REQUEST message. + */ +class BarrierRequest: public OFMsg { +public: + BarrierRequest(); + BarrierRequest(uint32_t xid); + ~BarrierRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_BARRIER_REPLY message*/ +class BarrierReply: public OFMsg { +public: + BarrierReply(); + BarrierReply(uint32_t xid); + ~BarrierReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_QUEUE_GET_CONFIG_REQUEST message. + */ +class QueueGetConfigRequest: public OFMsg { +private: + uint32_t port_; +public: + QueueGetConfigRequest(); + QueueGetConfigRequest(uint32_t xid, uint32_t port); + ~QueueGetConfigRequest() { + } + bool operator==(const QueueGetConfigRequest &other) const; + bool operator!=(const QueueGetConfigRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } +}; + +/** + OpenFlow 1.3 OFPT_QUEUE_GET_CONFIG_REPLY message. + */ +class QueueGetConfigReply: public OFMsg { +private: + uint32_t port_; + std::list queues_; +public: + QueueGetConfigReply(); + QueueGetConfigReply(uint32_t xid, uint32_t port); + QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues); + ~QueueGetConfigReply() { + } + bool operator==(const QueueGetConfigReply &other) const; + bool operator!=(const QueueGetConfigReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port() { + return this->port_; + } + std::list queues() { + return this->queues_; + } + void port(uint32_t port) { + this->port_ = port; + } + void queues(std::list queues); + void add_queue(PacketQueue queue); + size_t queues_len(); +}; + +/** + OpenFlow 1.3 OFPT_ROLE_REQUEST message. + */ +class RoleRequest: public RoleCommon { +public: + RoleRequest(); + RoleRequest(uint32_t xid, uint32_t role, uint64_t generation_id); + ~RoleRequest() { + } +}; + +/** + OpenFlow 1.3 OFPT_ROLE_REPLY message. + */ +class RoleReply: public RoleCommon { +public: + RoleReply(); + RoleReply(uint32_t xid, uint32_t role, uint64_t generation_id); + ~RoleReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_GET_ASYNC_REQUEST message. + */ +class GetAsyncRequest: public OFMsg { +public: + GetAsyncRequest(); + GetAsyncRequest(uint32_t xid); + ~GetAsyncRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_GET_ASYNC_REPLY message. + */ +class GetAsyncReply: public AsyncConfigCommon { +public: + GetAsyncReply(); + GetAsyncReply(uint32_t xid); + GetAsyncReply(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + ~GetAsyncReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_SET_ASYNC message. + */ +class SetAsync: public AsyncConfigCommon { +public: + SetAsync(); + SetAsync(uint32_t xid); + SetAsync(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + ~SetAsync() { + } +}; + +class MeterMod: public OFMsg { +private: + uint16_t command_; + uint16_t flags_; + uint32_t meter_id_; + MeterBandList bands_; + +public: + MeterMod(); + MeterMod(uint32_t xid, uint16_t command, uint16_t flags, uint32_t meter_id); + MeterMod(uint32_t xid, uint16_t command, uint16_t flags, uint32_t meter_id, + MeterBandList bands); + ~MeterMod() { + } + bool operator==(const MeterMod &other) const; + bool operator!=(const MeterMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command() { + return this->command_; + } + uint16_t flags() { + return this->flags_; + } + uint32_t meter_id() { + return this->meter_id_; + } + MeterBandList bands() { + return this->bands_; + } + void command(uint16_t command) { + this->command_ = command; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } + void bands(MeterBandList bands); + void add_band(MeterBand * band); +}; + +} // end of namespace of13 +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/ofcommon/action.hh b/include/libfluid-msg/ofcommon/action.hh new file mode 100644 index 00000000..5fb6376b --- /dev/null +++ b/include/libfluid-msg/ofcommon/action.hh @@ -0,0 +1,123 @@ +#ifndef ACTION_H +#define ACTION_H + +#include +#include +#include "../util/util.h" +#include "openflow-common.hh" + +namespace fluid_msg { + +class Action { +protected: + uint16_t type_; + uint16_t length_; +public: + Action(); + Action(uint16_t type, uint16_t length); + virtual ~Action() { + } + ; + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + virtual bool equals(const Action & other); + virtual bool operator==(const Action &other) const; + virtual bool operator!=(const Action &other) const; + virtual Action* clone() { + return new Action(*this); + } + virtual uint16_t set_order() const { + return 0; + } + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static Action * make_of10_action(uint16_t type); + static Action * make_of13_action(uint16_t type); + static bool delete_all(Action * action) { + delete action; + return true; + } + +}; + +class ActionList { +private: + uint16_t length_; + std::list action_list_; +public: + ActionList() + : length_(0) { + } + ; + ActionList(std::list action_list); + ActionList(const ActionList &other); + bool operator==(const ActionList &other) const; + bool operator!=(const ActionList &other) const; + ActionList& operator=(ActionList other); + ~ActionList(); + size_t pack(uint8_t *buffer); + of_error unpack10(uint8_t *buffer); + of_error unpack13(uint8_t *buffer); + friend void swap(ActionList& first, ActionList& second); + uint16_t length() { + return this->length_; + } + std::list action_list(){ + return this->action_list_; + } + void add_action(Action &action); + void add_action(Action *act); + void length(uint16_t length) { + this->length_ = length; + } +}; + +struct comp_action_set_order { + bool operator()(Action * lhs, Action* rhs) const { + return lhs->set_order() < rhs->set_order(); + } +}; + +class ActionSet { +private: + uint16_t length_; + std::set action_set_; +public: + ActionSet() + : length_(0) { + } + ; + ActionSet(std::set action_set); + ActionSet(const ActionSet &other); + bool operator==(const ActionSet &other) const; + bool operator!=(const ActionSet &other) const; + ActionSet& operator=(ActionSet other); + ~ActionSet(); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + friend void swap(ActionSet& first, ActionSet& second); + uint16_t length() { + return this->length_; + } + std::set action_set(){ + return this->action_set_; + } + void add_action(Action &action); + void add_action(Action *act); + void length(uint16_t length) { + this->length_ = length; + } +}; + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/ofcommon/common.hh b/include/libfluid-msg/ofcommon/common.hh new file mode 100644 index 00000000..0244bf75 --- /dev/null +++ b/include/libfluid-msg/ofcommon/common.hh @@ -0,0 +1,544 @@ +#pragma once + +#include +#include +#include "action.hh" +#include "../util/util.h" +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" + +namespace fluid_msg { + +class PortCommon { +protected: + EthAddress hw_addr_; + std::string name_; + uint32_t config_; + uint32_t state_; + uint32_t curr_; + uint32_t advertised_; + uint32_t supported_; + uint32_t peer_; +public: + PortCommon(); + PortCommon(EthAddress hw_addr, std::string name, uint32_t config, + uint32_t state, uint32_t curr, uint32_t advertised, uint32_t supported, + uint32_t peer); + ~PortCommon() { + } + bool operator==(const PortCommon &other) const; + bool operator!=(const PortCommon &other) const; + EthAddress hw_addr() { + return this->hw_addr_; + } + std::string name() { + return this->name_; + } + uint32_t config() { + return this->config_; + } + uint32_t state() { + return this->state_; + } + uint32_t curr() { + return this->curr_; + } + uint32_t advertised() { + return this->advertised_; + } + uint32_t supported() { + return this->supported_; + } + uint32_t peer() { + return this->peer_; + } + void hw_addr(EthAddress hw_addr) { + this->hw_addr_ = hw_addr; + } + void name(std::string name) { + this->name_ = name; + } + void config(uint32_t config) { + this->config_ = config; + } + void state(uint32_t state) { + this->state_ = state; + } + void curr(uint32_t curr) { + this->curr_ = curr; + } + void advertised(uint32_t advertised) { + this->advertised_ = advertised; + } + void supported(uint32_t supported) { + this->supported_ = supported; + } + void peer(uint32_t peer) { + this->peer_ = peer; + } + +}; + +class QueueProperty { +protected: + uint16_t property_; + uint16_t len_; +public: + QueueProperty(); + QueueProperty(uint16_t property); + virtual ~QueueProperty() { + } + ; + virtual bool equals(const QueueProperty & other); + virtual bool operator==(const QueueProperty &other) const; + virtual bool operator!=(const QueueProperty &other) const; + virtual QueueProperty* clone() { + return new QueueProperty(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t property() { + return this->property_; + } + uint16_t len() { + return this->len_; + } + void property(uint16_t property) { + this->property_ = property; + } + static QueueProperty* make_queue_of10_property(uint16_t property); + static QueueProperty* make_queue_of13_property(uint16_t property); + static bool delete_all(QueueProperty * prop) { + delete prop; + return true; + } +}; + +class QueuePropertyList { +private: + uint16_t length_; + std::list property_list_; +public: + QueuePropertyList() + : length_(0) { + } + ; + QueuePropertyList(std::list prop_list); + QueuePropertyList(const QueuePropertyList &other); + QueuePropertyList& operator=(QueuePropertyList other); + ~QueuePropertyList(); + bool operator==(const QueuePropertyList &other) const; + bool operator!=(const QueuePropertyList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack10(uint8_t* buffer); + of_error unpack13(uint8_t* buffer); + friend void swap(QueuePropertyList& first, QueuePropertyList& second); + uint16_t length() { + return this->length_; + } + std::list property_list() { + return this->property_list_; + } + void add_property(QueueProperty *prop); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class QueuePropRate: public QueueProperty { +protected: + uint16_t rate_; +public: + QueuePropRate(); + QueuePropRate(uint16_t property); + QueuePropRate(uint16_t property, uint16_t rate); + ~QueuePropRate() { + } + ; + virtual bool equals(const QueueProperty & other); + virtual QueuePropRate* clone() { + return new QueuePropRate(*this); + } + uint16_t rate() { + return this->rate_; + } + void rate(uint16_t rate) { + this->rate_ = rate; + } +}; + +class SwitchDesc { +private: + std::string mfr_desc_; + std::string hw_desc_; + std::string sw_desc_; + std::string serial_num_; + std::string dp_desc_; +public: + SwitchDesc() { + } + ; + SwitchDesc(std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc); + ~SwitchDesc() { + } + ; + bool operator==(const SwitchDesc &other) const; + bool operator!=(const SwitchDesc &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::string mfr_desc() { + return this->mfr_desc_; + } + std::string hw_desc() { + return this->hw_desc_; + } + std::string sw_desc() { + return this->sw_desc_; + } + std::string serial_num() { + return this->serial_num_; + } + std::string dp_desc() { + return this->dp_desc_; + } + void mfr_desc(std::string mfr_desc) { + this->mfr_desc_ = mfr_desc; + } + void hw_desc(std::string hw_desc) { + this->hw_desc_ = hw_desc; + } + void sw_desc(std::string sw_desc) { + this->sw_desc_ = sw_desc; + } + void serial_num(std::string serial_num) { + this->serial_num_ = serial_num; + } + void dp_desc(std::string dp_desc) { + this->dp_desc_ = dp_desc; + } + +}; + +/* Queue description*/ +class PacketQueueCommon { +protected: + uint32_t queue_id_; + uint16_t len_; + QueuePropertyList properties_; +public: + PacketQueueCommon(); + PacketQueueCommon(uint32_t queue_id); + virtual ~PacketQueueCommon() { + } + ; + bool operator==(const PacketQueueCommon &other) const; + bool operator!=(const PacketQueueCommon &other) const; + uint32_t queue_id() { + return this->queue_id_; + } + uint16_t len() { + return this->len_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } + void property(QueuePropertyList properties); + void add_property(QueueProperty* qp); +}; + +class FlowStatsCommon { +protected: + uint16_t length_; + uint8_t table_id_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + uint16_t priority_; + uint16_t idle_timeout_; + uint16_t hard_timeout_; + uint64_t cookie_; + uint64_t packet_count_; + uint64_t byte_count_; +public: + FlowStatsCommon(); + FlowStatsCommon(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count); + ~FlowStatsCommon() { + } + ; + bool operator==(const FlowStatsCommon &other) const; + bool operator!=(const FlowStatsCommon &other) const; + uint16_t length() { + return this->length_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + uint16_t priority() { + return this->priority_; + } + uint16_t idle_timeout() { + return this->idle_timeout_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void packet_count(uint16_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } +}; + +class TableStatsCommon { +protected: + uint8_t table_id_; + uint32_t active_count_; + uint64_t lookup_count_; + uint64_t matched_count_; +public: + TableStatsCommon(); + TableStatsCommon(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count); + ~TableStatsCommon() { + } + ; + bool operator==(const TableStatsCommon &other) const; + bool operator!=(const TableStatsCommon &other) const; + uint8_t table_id() { + return this->table_id_; + } + uint32_t active_count() { + return this->active_count_; + } + uint64_t lookup_count() { + return this->lookup_count_; + } + uint64_t matched_count() { + return this->matched_count_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void active_count(uint32_t active_count) { + this->active_count_ = active_count; + } + void lookup_count(uint64_t lookup_count) { + this->lookup_count_ = lookup_count; + } + void matched_count(uint64_t matched_count) { + this->matched_count_ = matched_count; + } +}; + +struct port_rx_tx_stats { + 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. */ + + bool operator==(const struct port_rx_tx_stats other) const { + return ((this->rx_packets == other.rx_packets) + && (this->tx_packets == other.tx_packets) + && (this->rx_bytes == other.rx_bytes) + && (this->tx_bytes == other.tx_bytes) + && (this->rx_dropped == other.rx_dropped) + && (this->tx_dropped == other.tx_dropped)); + } +}; + +struct port_err_stats { + 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. */ + + bool operator==(const struct port_err_stats other) const { + return ((this->rx_errors == other.rx_errors) + && (this->tx_errors == other.tx_errors) + && (this->rx_frame_err == other.rx_frame_err) + && (this->rx_over_err == other.rx_over_err) + && (this->rx_crc_err == other.rx_crc_err)); + } +}; + +class PortStatsCommon { +protected: + struct port_rx_tx_stats rx_tx_stats; + struct port_err_stats err_stats; + uint64_t collisions_; /* Number of collisions. */ +public: + PortStatsCommon(); + PortStatsCommon(struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions); + ~PortStatsCommon() { + } + ; + bool operator==(const PortStatsCommon &other) const; + bool operator!=(const PortStatsCommon &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t rx_packets() { + return this->rx_tx_stats.rx_packets; + } + uint64_t tx_packets() { + return this->rx_tx_stats.tx_packets; + } + uint64_t rx_bytes() { + return this->rx_tx_stats.rx_bytes; + } + uint64_t tx_bytes() { + return this->rx_tx_stats.tx_bytes; + } + uint64_t rx_dropped() { + return this->rx_tx_stats.rx_dropped; + } + uint64_t tx_dropped() { + return this->rx_tx_stats.tx_dropped; + } + uint64_t rx_errors() { + return this->err_stats.rx_errors; + } + uint64_t tx_errors() { + return this->err_stats.tx_errors; + } + uint64_t rx_frame_err() { + return this->err_stats.rx_frame_err; + } + uint64_t rx_over_err() { + return this->err_stats.rx_over_err; + } + uint64_t rx_crc_err() { + return this->err_stats.rx_crc_err; + } + uint64_t collisions() { + return this->collisions_; + } + void rx_packets(uint64_t rx_packets) { + this->rx_tx_stats.rx_packets = rx_packets; + } + void tx_packets(uint64_t tx_packets) { + this->rx_tx_stats.tx_packets = tx_packets; + } + void rx_bytes(uint64_t rx_bytes) { + this->rx_tx_stats.rx_bytes = rx_bytes; + } + void tx_bytes(uint64_t tx_bytes) { + this->rx_tx_stats.tx_bytes = tx_bytes; + } + void rx_dropped(uint64_t rx_dropped) { + this->rx_tx_stats.rx_dropped = rx_dropped; + } + void tx_dropped(uint64_t tx_dropped) { + this->rx_tx_stats.tx_dropped = tx_dropped; + } + void rx_errors(uint64_t rx_errors) { + this->err_stats.rx_errors = rx_errors; + } + void tx_errors(uint64_t tx_errors) { + this->err_stats.tx_errors = tx_errors; + } + void rx_frame_err(uint64_t rx_frame_err) { + this->err_stats.rx_frame_err = rx_frame_err; + } + void rx_over_err(uint64_t rx_over_err) { + this->err_stats.rx_over_err = rx_over_err; + } + void rx_crc_err(uint64_t rx_crc_err) { + this->err_stats.rx_crc_err = rx_crc_err; + } + void collisions(uint64_t collisions) { + this->collisions_ = collisions; + } +}; + +class QueueStatsCommon { +protected: + uint32_t queue_id_; + uint64_t tx_bytes_; + uint64_t tx_packets_; + uint64_t tx_errors_; +public: + QueueStatsCommon(); + QueueStatsCommon(uint32_t queue_id, uint64_t tx_bytes, uint64_t tx_packets, + uint64_t tx_errors); + ~QueueStatsCommon() { + } + ; + bool operator==(const QueueStatsCommon &other) const; + bool operator!=(const QueueStatsCommon &other) const; + uint32_t queue_id() { + return this->queue_id_; + } + uint64_t tx_bytes() { + return this->tx_bytes_; + } + uint64_t tx_packets() { + return this->tx_packets_; + } + uint64_t tx_errors() { + return this->tx_errors_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } + void tx_bytes(uint64_t tx_bytes) { + this->tx_bytes_ = tx_bytes; + } + void tx_packets(uint64_t tx_packets) { + this->tx_packets_ = tx_packets; + } + void tx_errors(uint64_t tx_errors) { + this->tx_errors_ = tx_errors; + } +}; + +} // End of namespace fluid_msg diff --git a/include/libfluid-msg/ofcommon/msg.hh b/include/libfluid-msg/ofcommon/msg.hh new file mode 100644 index 00000000..071b3d8f --- /dev/null +++ b/include/libfluid-msg/ofcommon/msg.hh @@ -0,0 +1,493 @@ +#ifndef MSG_H +#define MSG_H 1 + +#include "../util/ethaddr.hh" +#include "action.hh" +#include "openflow-common.hh" + + +namespace fluid_msg { +class Action; +} + +namespace fluid_msg { +/** + Base class for OpenFlow messages. + */ +class OFMsg { +protected: + uint8_t version_; + uint8_t type_; + uint16_t length_; + uint32_t xid_; +public: + OFMsg(uint8_t version, uint8_t type); + OFMsg(uint8_t version, uint8_t type, uint32_t xid); + OFMsg(uint8_t* buffer) { + unpack(buffer); + } + virtual ~OFMsg() { + } + virtual uint8_t* pack(); + virtual of_error unpack(uint8_t *buffer); + bool operator==(const OFMsg &other) const; + bool operator!=(const OFMsg &other) const; + uint8_t version() { + return this->version_; + } + uint8_t type() { + return this->type_; + } + //Length is virtual because we need to override + //it in some classes where the length is padding + // dependent (e.g OpenFlow 1.3 Flow Mod). + virtual uint16_t length() { + return this->length_; + } + uint32_t xid() { + return this->xid_; + } + void version(uint8_t version) { + this->version_ = version; + } + void msg_type(uint8_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + void xid(uint32_t xid) { + this->xid_ = xid; + } + static void free_buffer(uint8_t *buffer) { + delete[] buffer; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Echo messages. + */ +class EchoCommon: public OFMsg { +private: + void *data_; + size_t data_len_; +public: + EchoCommon(uint8_t version, uint8_t type); + EchoCommon(uint8_t version, uint8_t type, uint32_t xid) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0) { + } + virtual ~EchoCommon(); + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + bool operator==(const EchoCommon &other) const; + bool operator!=(const EchoCommon &other) const; + void* data() { + return this->data_; + } + size_t data_len() { + return this->data_len_; + } + void data(void* data, size_t data_len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Error messages. + */ +class ErrorCommon: public OFMsg { +protected: + uint16_t err_type_; + uint16_t code_; + void* data_; + size_t data_len_; +public: + ErrorCommon(uint8_t version, uint8_t type); + ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, uint16_t err_type, + uint16_t code); + ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, uint16_t err_type, + uint16_t code, void* data, size_t data_len); + virtual ~ErrorCommon(); + bool operator==(const ErrorCommon &other) const; + bool operator!=(const ErrorCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t err_type() { + return this->err_type_; + } + uint16_t code() { + return this->code_; + } + void* data() { + return this->data_; + } + size_t data_len() { + return this->data_len_; + } + void err_type(uint16_t err_type) { + this->err_type_ = err_type; + } + void code(uint16_t code) { + this->code_ = code; + } + void data(void* data, size_t data_len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Features Reply messages. + */ +class FeaturesReplyCommon: public OFMsg { +protected: + uint64_t datapath_id_; + uint32_t n_buffers_; + uint8_t n_tables_; + uint32_t capabilities_; +public: + FeaturesReplyCommon(uint8_t version, uint8_t type); + FeaturesReplyCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t datapath_id, uint32_t n_buffers, uint8_t n_tables, + uint32_t capabilities); + virtual ~FeaturesReplyCommon() { + } + bool operator==(const FeaturesReplyCommon &other) const; + bool operator!=(const FeaturesReplyCommon &other) const; + uint64_t datapath_id() { + return this->datapath_id_; + } + uint32_t n_buffers() { + return this->n_buffers_; + } + uint8_t n_tables() { + return this->n_tables_; + } + uint32_t capabilities() { + return this->capabilities_; + } + void datapath_id(uint64_t datapath_id) { + this->datapath_id_ = datapath_id; + } + void n_buffers(uint32_t n_buffers) { + this->n_buffers_ = n_buffers; + } + void n_tables(uint8_t n_tables) { + this->n_tables_ = n_tables; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Features Switch Config messages. + */ +class SwitchConfigCommon: public OFMsg { +private: + uint16_t flags_; + uint16_t miss_send_len_; +public: + SwitchConfigCommon(uint8_t version, uint8_t type); + SwitchConfigCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t flags, uint16_t miss_send_len); + virtual ~SwitchConfigCommon() { + } + bool operator==(const SwitchConfigCommon &other) const; + bool operator!=(const SwitchConfigCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t flags() { + return this->flags_; + } + uint16_t miss_send_len() { + return this->miss_send_len_; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } + void miss_send_len(uint16_t miss_send_len) { + this->miss_send_len_ = miss_send_len; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Flow Mod messages. + */ +class FlowModCommon: public OFMsg { +protected: + uint64_t cookie_; + uint16_t idle_timeout_; + uint16_t hard_timeout_; + uint16_t priority_; + uint32_t buffer_id_; + uint16_t flags_; + +public: + FlowModCommon(uint8_t version, uint8_t type); + FlowModCommon(uint8_t version, uint8_t type, uint32_t xid, uint64_t cookie, + uint16_t idle_timeout, uint16_t hard_timeout, + uint16_t priority, uint32_t buffer_id, uint16_t flags); + virtual ~FlowModCommon() { + } + ; + bool operator==(const FlowModCommon &other) const; + bool operator!=(const FlowModCommon &other) const; + uint64_t cookie() { + return this->cookie_; + } + uint16_t idle_timeout() { + return this->idle_timeout_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + uint16_t priority() { + return this->priority_; + } + uint32_t buffer_id() { + return this->buffer_id_; + } + uint16_t flags() { + return this->flags_; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Packet Out messages. + */ +class PacketOutCommon: public OFMsg { +protected: + uint32_t buffer_id_; + uint16_t actions_len_; + ActionList actions_; + void* data_; + size_t data_len_; +public: + PacketOutCommon(uint8_t version, uint8_t type); + PacketOutCommon(uint8_t version, uint16_t type, uint32_t xid, + uint32_t buffer_id); + virtual ~PacketOutCommon(); + bool operator==(const PacketOutCommon &other) const; + bool operator!=(const PacketOutCommon &other) const; + uint32_t buffer_id() { + return this->buffer_id_; + } + uint16_t actions_len() { + return this->actions_len_; + } + ActionList actions() { + return this->actions_; + } + size_t data_len() { + return this->data_len_; + } + void* data() { + return this->data_; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action *action); + void data(void* data, size_t len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Packet In messages. + */ +class PacketInCommon: public OFMsg { +protected: + uint32_t buffer_id_; + uint16_t total_len_; + uint8_t reason_; + size_t data_len_; + void* data_; +public: + PacketInCommon(uint8_t version, uint8_t type); + PacketInCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t buffer_id, uint16_t total_len, uint8_t reason); + virtual ~PacketInCommon(); + bool operator==(const PacketInCommon &other) const; + bool operator!=(const PacketInCommon &other) const; + uint32_t buffer_id() const { + return this->buffer_id_; + } + uint16_t total_len() { + return this->total_len_; + } + uint8_t reason() const { + return this->reason_; + } + void* data() const { + return this->data_; + } + size_t data_len() const { + return this->data_len_; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void total_len(uint16_t total_len) { + this->total_len_ = total_len; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } + void data(void* data, size_t len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Flow Removed messages. + */ +class FlowRemovedCommon: public OFMsg { +protected: + uint64_t cookie_; + uint16_t priority_; + uint8_t reason_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + uint16_t idle_timeout_; + uint64_t packet_count_; + uint64_t byte_count_; +public: + FlowRemovedCommon(uint8_t version, uint8_t type); + FlowRemovedCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t cookie, uint16_t priority, uint8_t reason, + uint32_t duration_sec, uint32_t duration_nsec, uint16_t idle_timeout, + uint64_t packet_count, uint64_t byte_count); + virtual ~FlowRemovedCommon() { + } + bool operator==(const FlowRemovedCommon &other) const; + bool operator!=(const FlowRemovedCommon &other) const; + uint64_t cookie() { + return this->cookie_; + } + uint16_t priority() { + return this->priority_; + } + uint8_t reason() { + return this->reason_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Port Status messages. + */ +class PortStatusCommon: public OFMsg { +protected: + uint8_t reason_; +public: + PortStatusCommon(uint8_t version, uint8_t type); + PortStatusCommon(uint8_t version, uint8_t type, uint32_t xid, + uint8_t reason); + virtual ~PortStatusCommon() { + } + bool operator==(const PortStatusCommon &other) const; + bool operator!=(const PortStatusCommon &other) const; + uint8_t reason() { + return this->reason_; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Port Mod messages. + */ +class PortModCommon: public OFMsg { +protected: + EthAddress hw_addr_; + uint32_t config_; + uint32_t mask_; + uint32_t advertise_; +public: + PortModCommon(uint8_t version, uint8_t type); + PortModCommon(uint8_t version, uint8_t type, uint32_t xid, + EthAddress hw_addr, uint32_t config, uint32_t mask, uint32_t advertise); + virtual ~PortModCommon() { + } + bool operator==(const PortModCommon &other) const; + bool operator!=(const PortModCommon &other) const; + EthAddress hw_addr() { + return this->hw_addr_; + } + uint32_t config() { + return this->config_; + } + uint32_t mask() { + return this->mask_; + } + uint32_t advertise() { + return this->advertise_; + } + void hw_addr(EthAddress hw_addr) { + this->hw_addr_ = hw_addr; + } + void config(uint32_t config) { + this->config_ = config; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } + void advertise(uint32_t advertise) { + this->advertise_ = advertise; + } +}; + +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/ofcommon/openflow-common.hh b/include/libfluid-msg/ofcommon/openflow-common.hh new file mode 100644 index 00000000..30c4d132 --- /dev/null +++ b/include/libfluid-msg/ofcommon/openflow-common.hh @@ -0,0 +1,161 @@ +#ifndef OPENFLOW_OPENFLOWCOMMON_H +#define OPENFLOW_OPENFLOWCOMMON_H 1 + +#ifdef __KERNEL__ +#include +#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 uint8_t OFP_ASSERT(EXPR) \ + 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 +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +namespace fluid_msg { + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_header. */ + uint32_t xid; /* Transaction id associated with this packet. + Replies use the same id as was in the request + total_len facilitate pairing. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_header) == 8); + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_fluid_error_msg { + struct ofp_fluid_header header; + 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_fluid_error_msg) == 12); + +/* Switch configuration. */ +struct ofp_fluid_switch_config { + struct ofp_fluid_header header; + uint16_t flags; /* OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of new flow that datapath should + send to the controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_switch_config) == 12); + +/* 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); + +/* 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); + +const uint16_t DESC_FLUID_STR_LEN = 256; +const uint8_t SERIAL_FLUID_NUM_LEN = 32; + +/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated + * ASCII string. */ +struct ofp_desc { + char mfr_desc[DESC_FLUID_STR_LEN]; /* Manufacturer description. */ + char hw_desc[DESC_FLUID_STR_LEN]; /* Hardware description. */ + char sw_desc[DESC_FLUID_STR_LEN]; /* Software description. */ + char serial_num[SERIAL_FLUID_NUM_LEN]; /* Serial number. */ + char dp_desc[DESC_FLUID_STR_LEN]; /* Human readable description of datapath. */ +}; +OFP_ASSERT(sizeof(struct ofp_desc) == 1056); + +/* Role request and reply message. */ +struct ofp_role_request { + struct ofp_fluid_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_fluid_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); + +const uint8_t OFP_FLUID_MAX_TABLE_NAME_LEN = 32; +const uint8_t OFP_MAX_PORT_NAME_LEN = 16; +const uint16_t OFP_TCP_PORT = 6653; +const uint16_t OFP_SSL_PORT = 6653; +const uint8_t OFP_ETH_ALEN = 6; /* Bytes in an Ethernet address. */ +const uint8_t OFP_FLUID_DEFAULT_MISS_SEND_LEN = 128; +/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry + * is permanent. */ +const uint8_t OFP_FLUID_FLOW_PERMANENT = 0; +/* By default, choose a priority in the middle. */ +const uint16_t OFP_FLUID_DEFAULT_PRIORITY = 0x8000; +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +const uint32_t OFPQ_FLUID_ALL = 0xffffffff; +/* Min rate > 1000 means not configured. */ +const uint16_t OFPQ_MIN_RATE_UNCFG = 0xffff; + +typedef uint32_t of_error; + +const uint32_t OF_ERROR = 0xffffffff; + +/* Creates an of_error from an OpenFlow error type and code */ +static inline of_error openflow_error(uint16_t type, uint16_t code) { + /* NOTE: highest bit is always set to one, so no error value is zero */ + uint32_t ret = type; + return 0x80000000 | ret << 16 | code; +} + +/* Returns the error type of an of_error */ +static inline uint16_t of_error_type(of_error error) { + return (0x7fff0000 & error) >> 16; +} + +/* Returns the error code of an of_error */ +static inline uint16_t of_error_code(of_error error) { + return error & 0x0000ffff; +} + +typedef uint32_t of_err; + +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/util/ethaddr.hh b/include/libfluid-msg/util/ethaddr.hh new file mode 100644 index 00000000..6a9c3052 --- /dev/null +++ b/include/libfluid-msg/util/ethaddr.hh @@ -0,0 +1,37 @@ +#ifndef __MACADDRESS_H__ +#define __MACADDRESS_H__ + +#include +#include +#include + +#include +#include +#include + +namespace fluid_msg{ + +class EthAddress { + public: + EthAddress(); + EthAddress(const char* address); + EthAddress(const std::string &address); + EthAddress(const EthAddress &other); + EthAddress(const uint8_t* data); + + EthAddress& operator=(const EthAddress &other); + bool operator==(const EthAddress &other) const; + std::string to_string() const; + void set_data(uint8_t* array); + uint8_t* get_data(){return this->data;} + static uint8_t* data_from_string(const std::string &address); + + private: + uint8_t data[6]; + // void data_from_string(const std::string &address); +}; +} +#endif /* __MACADDRESS_H__ */ + + + diff --git a/include/libfluid-msg/util/ipaddr.hh b/include/libfluid-msg/util/ipaddr.hh new file mode 100644 index 00000000..c2771615 --- /dev/null +++ b/include/libfluid-msg/util/ipaddr.hh @@ -0,0 +1,45 @@ +#ifndef __IPADDRESS_H__ +#define __IPADDRESS_H__ + +#include +#include +#include +#include +#include +#include + +namespace fluid_msg{ + +enum {NONE = 0, IPV4 = 4, IPV6 = 6 }; + +class IPAddress { + public: + IPAddress(); + IPAddress(const char* address); + IPAddress(const std::string &address); + IPAddress(const IPAddress &other); + IPAddress(const uint32_t ip_addr); + IPAddress(const uint8_t ip_addr[16]); + IPAddress(const struct in_addr& ip_addr); + IPAddress(const struct in6_addr& ip_addr); + ~IPAddress(){}; + + IPAddress& operator=(const IPAddress& other); + bool operator==(const IPAddress& other) const; + int get_version() const; + void setIPv4(uint32_t address); + void setIPv6(uint8_t address[16]); + uint32_t getIPv4(); + uint8_t * getIPv6(); + static uint32_t IPv4from_string(const std::string &address); + static struct in6_addr IPv6from_string(const std::string &address); + + private: + int version; + union { + uint32_t ipv4; + uint8_t ipv6[16]; + }; +}; +} +#endif /* __IPADDRESS_H__ */ diff --git a/include/libfluid-msg/util/util.h b/include/libfluid-msg/util/util.h new file mode 100644 index 00000000..f435eba9 --- /dev/null +++ b/include/libfluid-msg/util/util.h @@ -0,0 +1,170 @@ +/* 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 UTIL_H +#define UTIL_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(dst, src) ((dst) = (src)) +#endif +#endif + + +#ifndef __cplusplus +/* Build-time assertion for use in a statement context. */ +#define BUILD_ASSERT(EXPR) \ + sizeof(struct { unsigned int build_assert_failed : (EXPR) ? 1 : -1; }) + +/* Build-time assertion for use in a declaration context. */ +#define BUILD_ASSERT_DECL(EXPR) \ + extern int (*build_assert(void))[BUILD_ASSERT(EXPR)] +#else /* __cplusplus */ +#endif /* __cplusplus */ + +#define NO_RETURN __attribute__((__noreturn__)) +#define UNUSED __attribute__((__unused__)) +#define PACKED __attribute__((__packed__)) +//#define PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1))) +#define STRFTIME_FORMAT(FMT) __attribute__((__format__(__strftime__, FMT, 0))) +#define MALLOC_LIKE __attribute__((__malloc__)) +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +#define ARRAY_SIZE(ARRAY) (sizeof ARRAY / sizeof *ARRAY) +#define ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y) * (Y)) +#define ROUND_DOWN(X, Y) ((X) / (Y) * (Y)) +#define IS_POW2(X) ((X) && !((X) & ((X) - 1))) + +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif + +#define NOT_REACHED() abort() +#define NOT_IMPLEMENTED() abort() +#define NOT_TESTED() ((void) 0) /* XXX should print a message. */ + +/* Given POINTER, the address of the given MEMBER in a STRUCT object, returns + the STRUCT object. */ +#define CONTAINER_OF(POINTER, STRUCT, MEMBER) \ + ((STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER))) + +/* Check endianness on OS X. */ +#ifndef __BYTE_ORDER +#define __BYTE_ORDER __BYTE_ORDER__ +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static inline uint16_t +hton16(uint16_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return htons(n); +#endif +} + +static inline uint16_t +ntoh16(uint16_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return ntohs(n); +#endif +} + +static inline uint32_t +hton32(uint32_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return htonl(n); +#endif +} + +static inline uint32_t +ntoh32(uint32_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return ntohl(n); +#endif +} + +static inline uint64_t +hton64(uint64_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return (((uint64_t)hton32(n)) << 32) + hton32(n >> 32); +#endif +} + +static inline uint64_t +ntoh64(uint64_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return (((uint64_t)ntoh32(n)) << 32) + ntoh32(n >> 32); +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* util.h */ diff --git a/include/of_controller.h b/include/of_controller.h new file mode 100644 index 00000000..05613c1a --- /dev/null +++ b/include/of_controller.h @@ -0,0 +1,80 @@ +#pragma once + +#include "of_message.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP + +#include "libfluid-base/OFServer.hh" +#include "libfluid-msg/of10msg.hh" +#include "libfluid-msg/of13msg.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fluid_base; +using namespace fluid_msg; + +class OFController : public OFServer { +public: + OFController(const std::unordered_map switch_dpid_map, + const char* address = "0.0.0.0", + const int port = 1234, + const int nthreads = 8, + bool secure = false) : + xid(0), + switch_dpid_map(switch_dpid_map), + OFServer(address, port, nthreads, secure, + OFServerSettings().supported_version(5) + .echo_interval(30)) { } + + ~OFController() = default; + + void stop() override; + + void message_callback(OFConnection* ofconn, uint8_t type, void* data, size_t len) override; + + void connection_callback(OFConnection* ofconn, OFConnection::Event type) override; + + OFConnection* get_instance(std::string bridge); + + void add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn); + + void remove_switch_from_conn_map(std::string bridge); + + void remove_switch_from_conn_map(int ofconn_id); + + void send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p); + + void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); + +private: + // tracking xid (ovs transaction id) + std::atomic xid; + + // k is bridge name like 'br-int', v is OFConnection* obj + std::unordered_map switch_conn_map; + + // k is ofconnection id like '0', v is bridge name associated with it + std::unordered_map switch_id_map; + + // k is dpid (query from ovs), v is bridge name associated with it + std::unordered_map switch_dpid_map; + + std::mutex switch_map_mutex; +}; diff --git a/include/of_message.h b/include/of_message.h new file mode 100644 index 00000000..0e324001 --- /dev/null +++ b/include/of_message.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include +#include +#include + +class OFRawBuf { +public: + virtual ~OFRawBuf() = default; + virtual void* data() = 0; + virtual size_t len() = 0; +}; + +class OFMessage { +public: + virtual ~OFMessage() = default; + // xid + virtual uint32_t xid() = 0; + virtual void set_xid(uint32_t id) = 0; + // pack + virtual std::shared_ptr pack() = 0; +}; + +typedef uint32_t ofmsg_xid_t; +typedef std::shared_ptr ofmsg_ptr_t; + +class BundleFlowModMessage { +public: + BundleFlowModMessage(const std::vector flow_mods, std::atomic* fm_xid) : + _flow_mods(flow_mods), + _fm_xid(fm_xid) { } + + ~BundleFlowModMessage() = default; + + uint32_t get_bundle_id() { + return _bundle_id; + } + + std::shared_ptr pack_open_req(); + std::shared_ptr pack_commit_req(); + std::vector > pack_flow_mods(); + +private: + // bundle_id is generated from BundleCtrlMessage->pack() + uint32_t _bundle_id; + // starting x_id (auto increased for each message in this bundle, so all unique) + // need to sync auto increased value with caller for overall OF msg xid management + std::atomic* _fm_xid; + // each flow mod message may have different op_type, like bundling add/mod/delete flow operations together + std::vector _flow_mods; +}; + +class BundleReplyMessage { +public: + BundleReplyMessage() { } + + ~BundleReplyMessage() = default; + + uint32_t get_bundle_id() { + return _bundle_id; + } + + uint16_t get_type() { + return _type; + } + + void unpack(void* data); + +private: + uint32_t _bundle_id; + + uint16_t _type; +}; + +ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle = false); +ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict, bool bundle = false); +ofmsg_ptr_t create_del_flow(const std::string& match, bool strict, bool bundle = false); +std::vector create_add_flows(const std::vector& flows, bool bundle = false); diff --git a/include/ovs_control.h b/include/ovs_control.h index fbdc75e7..2eb4d894 100644 --- a/include/ovs_control.h +++ b/include/ovs_control.h @@ -12,144 +12,157 @@ // 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. - +#pragma once #ifndef OVS_CONTROL_H #define OVS_CONTROL_H #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define DSCP_DEFAULT (IPTOS_PREC_INTERNETCONTROL >> 2) -#define STDOUT_FILENO 1 /* Standard output. */ +#define STDOUT_FILENO 1 /* Standard output. */ #include /* add to /usr/local/include/openvswitch */ +#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include -extern "C" { - struct unixctl_conn; +extern "C" { +struct unixctl_conn; } + +// copy from ovs source code "include/openvswitch/ofp-table.h" +struct ofputil_table_map { + struct namemap map; +}; + +// copy from ovs source code "include/openvswitch/ofp-monitor.h" +char *parse_flow_monitor_request(struct ofputil_flow_monitor_request *, + const char *, const struct ofputil_port_map *, + const struct ofputil_table_map *, + enum ofputil_protocol *usable_protocols) OVS_WARN_UNUSED_RESULT; + // OVS implementation class namespace ovs_control { class OVS_Control { - public: - static OVS_Control &get_instance(); +public: + static OVS_Control &get_instance(); + + /* --names, --no-names: Show port and table names in output and accept them in + * input. (When neither is specified, the default is to accept port names but, + * for backward compatibility, not to show them unless this is an interactive + * console session.) */ + static int use_names; + static int verbosity; + static bool bundle; + /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ + static enum ofputil_protocol allowed_protocols; + /* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop" commands. */ + char *unixctl_path; + + /* + * structs and functions borrowed from ovs-ofctl.c + */ + void monitor(const char *bridge, const char *opt); + void packet_out(const char *bridge, const char *opt); + int dump_flows(const char *bridge, const char *flow, bool show_stats = true); + void dump_flows__(const char *bridge, const char *flow, bool aggregate); + int add_flow(const char *bridge, const char *flow); + int mod_flows(const char *bridge, const char *flow, bool strict); + int del_flows(const char *bridge, const char *flow, bool strict); + int flow_mod(const char *bridge, const char *flow, unsigned short int command); + void flow_mod__(const char *remote, struct ofputil_flow_mod *fms, + size_t n_fms, enum ofputil_protocol usable_protocols); + void bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, + size_t n_fms, enum ofputil_protocol usable_protocols); + vconn *prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, + ofputil_flow_stats_request *fsr, ofputil_protocol *protocolp); + enum ofputil_protocol + set_protocol_for_flow_dump(vconn *vconn, ofputil_protocol cur_protocol, + ofputil_protocol usable_protocols); + enum ofputil_protocol open_vconn_for_flow_mod(const char *remote, vconn **vconnp, + enum ofputil_protocol usable_protocols); + bool try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, + enum ofputil_protocol *cur); + void fetch_switch_config(vconn *vconn, ofputil_switch_config *config); + void set_switch_config(vconn *vconn, const ofputil_switch_config *config); + int open_vconn_socket(const char *name, vconn **vconnp); + void run(int retval, const char *message, ...); + enum ofputil_protocol open_vconn(const char *name, vconn **vconnp); + void bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, + const char *vconn_name); + void bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags); + void transact_noreply(vconn *vconn, ofpbuf *request); + void transact_multiple_noreply(vconn *vconn, ovs_list *requests); + int monitor_set_invalid_ttl_to_controller(vconn *vconn); + bool set_packet_in_format(vconn *vconn, enum nx_packet_in_format packet_in_format, + bool must_succeed); + void monitor_vconn(vconn *vconn, bool reply_to_echo_requests, + bool resume_continuations, const char *bridge); + void send_openflow_buffer(vconn *vconn, ofpbuf *buffer); + void dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge); -/* --names, --no-names: Show port and table names in output and accept them in - * input. (When neither is specified, the default is to accept port names but, - * for backward compatibility, not to show them unless this is an interactive - * console session.) */ - static int use_names; - static int verbosity; - static bool bundle; - /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ - static enum ofputil_protocol allowed_protocols; - /* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop" - commands. */ - char *unixctl_path; - - /* - * structs and funcntions borrow from ovs-ofctl.c - */ - void monitor(const char *bridge, const char *opt); - void packet_out(const char *bridge, const char *opt); - int dump_flows(const char *bridge, const char *flow, bool show_stats = true); - void dump_flows__(const char *bridge, const char *flow, bool aggregate); - int add_flow(const char *bridge, const char *flow); - int mod_flows(const char *bridge, const char *flow, bool strict); - int del_flows(const char *bridge, const char *flow, bool strict); - int flow_mod(const char *bridge, const char *flow, unsigned short int command); - void flow_mod__(const char *remote, struct ofputil_flow_mod *fms, - size_t n_fms, enum ofputil_protocol usable_protocols); - void bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, - size_t n_fms, enum ofputil_protocol usable_protocols); - vconn *prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, - ofputil_flow_stats_request *fsr, - ofputil_protocol *protocolp); - enum ofputil_protocol set_protocol_for_flow_dump(vconn *vconn, - ofputil_protocol cur_protocol, - ofputil_protocol usable_protocols); - enum ofputil_protocol open_vconn_for_flow_mod(const char *remote, vconn **vconnp, - enum ofputil_protocol usable_protocols); - bool try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, - enum ofputil_protocol *cur); - void fetch_switch_config(vconn *vconn, ofputil_switch_config *config); - void set_switch_config(vconn *vconn, const ofputil_switch_config *config); - int open_vconn_socket(const char *name, vconn **vconnp); - void run(int retval, const char *message, ...); - enum ofputil_protocol open_vconn(const char *name, vconn **vconnp); - void bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, - const char *vconn_name); - void bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags); - void transact_noreply(vconn *vconn, ofpbuf *request); - void transact_multiple_noreply(vconn *vconn, ovs_list *requests); - int monitor_set_invalid_ttl_to_controller(vconn *vconn); - bool set_packet_in_format(vconn *vconn, - enum ofputil_packet_in_format packet_in_format, - bool must_succeed); - void monitor_vconn(vconn *vconn, bool reply_to_echo_requests, - bool resume_continuations, const char *bridge); - void send_openflow_buffer(vconn *vconn, ofpbuf *buffer); - void dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge); - - struct barrier_aux { - struct vconn *vconn; /* OpenFlow connection for sending barrier. */ - struct unixctl_conn *conn; /* Connection waiting for barrier response. */ - }; + struct barrier_aux { + struct vconn *vconn; /* OpenFlow connection for sending barrier. */ + struct unixctl_conn *conn; /* Connection waiting for barrier response. */ + }; - enum PI { PI_FEATURES, PI_PORT_DESC }; - struct port_iterator { - struct vconn *vconn; - PI variant; - struct ofpbuf *reply; - ovs_be32 send_xid; - bool more; - }; - enum TI { TI_STATS, TI_FEATURES }; - struct table_iterator { - struct vconn *vconn; - TI variant; - struct ofpbuf *reply; - ovs_be32 send_xid; - bool more; + enum PI { PI_FEATURES, PI_PORT_DESC }; + struct port_iterator { + struct vconn *vconn; + PI variant; + struct ofpbuf *reply; + ovs_be32 send_xid; + bool more; + }; + enum TI { TI_STATS, TI_FEATURES }; + struct table_iterator { + struct vconn *vconn; + TI variant; + struct ofpbuf *reply; + ovs_be32 send_xid; + bool more; - struct ofputil_table_features features; - struct ofpbuf raw_properties; - }; + struct ofputil_table_features features; + struct ofpbuf raw_properties; + }; - ofp_port_t str_to_port_no(const char *vconn_name, const char *port_name); - bool str_to_ofp(const char *s, ofp_port_t *ofp_port); - void port_iterator_fetch_port_desc(port_iterator *pi); - void port_iterator_fetch_features(port_iterator *pi); - void port_iterator_init(port_iterator *pi, vconn *vconn); - bool port_iterator_next(port_iterator *pi, ofputil_phy_port *pp); - void port_iterator_destroy(port_iterator *pi); - void fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, ofputil_phy_port *pp); - const ofputil_port_map *get_port_map(const char *vconn_name); - const ofputil_port_map *ports_to_accept(const char *vconn_name); - const ofputil_port_map *ports_to_show(const char *vconn_name); - void table_iterator_init(table_iterator *ti, struct vconn *vconn); - const ofputil_table_features * table_iterator_next(table_iterator *ti); - void table_iterator_destroy(table_iterator *ti); - const ofputil_table_map *get_table_map(const char *vconn_name); - const ofputil_table_map *tables_to_accept(const char *vconn_name); - const ofputil_table_map *tables_to_show(const char *vconn_name); - bool should_accept_names(void); - bool should_show_names(void); - const char * openflow_from_hex(const char *hex, ofpbuf **msgp); + ofp_port_t str_to_port_no(const char *vconn_name, const char *port_name); + bool str_to_ofp(const char *s, ofp_port_t *ofp_port); + void port_iterator_fetch_port_desc(port_iterator *pi); + void port_iterator_fetch_features(port_iterator *pi); + void port_iterator_init(port_iterator *pi, vconn *vconn); + bool port_iterator_next(port_iterator *pi, ofputil_phy_port *pp); + void port_iterator_destroy(port_iterator *pi); + void fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, + ofputil_phy_port *pp); + const ofputil_port_map *get_port_map(const char *vconn_name); + const ofputil_port_map *ports_to_accept(const char *vconn_name); + const ofputil_port_map *ports_to_show(const char *vconn_name); + void table_iterator_init(table_iterator *ti, struct vconn *vconn); + const ofputil_table_features *table_iterator_next(table_iterator *ti); + void table_iterator_destroy(table_iterator *ti); + //const ofputil_table_map *get_table_map(const char *vconn_name); + //const ofputil_table_map *tables_to_accept(const char *vconn_name); + //const ofputil_table_map *tables_to_show(const char *vconn_name); + bool should_accept_names(void); + bool should_show_names(void); + const char *openflow_from_hex(const char *hex, ofpbuf **msgp); - // compiler will flag the error when below is called. - OVS_Control(OVS_Control const &) = delete; - void operator=(OVS_Control const &) = delete; + // compiler will flag the error when below is called. + OVS_Control(OVS_Control const &) = delete; + void operator=(OVS_Control const &) = delete; - private: - OVS_Control(){}; - ~OVS_Control(){}; +private: + OVS_Control(){}; + ~OVS_Control(){}; }; } // namespace ovs_control #endif // #ifndef OVS_CONTROL_H \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 485a950b..730cecb6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,21 +16,61 @@ set(SOURCES ./ovs/aca_vlan_manager.cpp ./ovs/ovs_control.cpp ./ovs/aca_ovs_control.cpp + ./ovs/aca_arp_responder.cpp + ./ovs/libfluid-base/base/BaseOFClient.cc + ./ovs/libfluid-base/base/BaseOFConnection.cc + ./ovs/libfluid-base/base/BaseOFServer.cc + ./ovs/libfluid-base/base/EventLoop.cc + ./ovs/libfluid-base/OFClient.cc + ./ovs/libfluid-base/OFConnection.cc + ./ovs/libfluid-base/OFServer.cc + ./ovs/libfluid-base/OFServerSettings.cc + ./ovs/libfluid-base/TLS.cc + ./ovs/libfluid-msg/of10/of10action.cc + ./ovs/libfluid-msg/of10/of10common.cc + ./ovs/libfluid-msg/of10/of10match.cc + ./ovs/libfluid-msg/of13/of13action.cc + ./ovs/libfluid-msg/of13/of13common.cc + ./ovs/libfluid-msg/of13/of13instruction.cc + ./ovs/libfluid-msg/of13/of13match.cc + ./ovs/libfluid-msg/of13/of13meter.cc + ./ovs/libfluid-msg/ofcommon/action.cc + ./ovs/libfluid-msg/ofcommon/common.cc + ./ovs/libfluid-msg/ofcommon/msg.cc + ./ovs/libfluid-msg/util/ethaddr.cc + ./ovs/libfluid-msg/util/ipaddr.cc + ./ovs/libfluid-msg/of10msg.cc + ./ovs/libfluid-msg/of13msg.cc + ./ovs/of_message.cpp + ./ovs/of_controller.cpp ./on_demand/aca_on_demand_engine.cpp ./dhcp/aca_dhcp_state_handler.cpp ./dhcp/aca_dhcp_server.cpp ./zeta/aca_zeta_oam_server.cpp - ./zeta/aca_zeta_programming.cpp - ./ovs/aca_arp_responder.cpp + ./zeta/aca_zeta_programming.cpp ) + +#Find libevent installation +find_path(LIBEVENT_INCLUDE_DIR + NAMES event2/thread.h + HINTS /usr/include + REQUIRED) + +FIND_LIBRARY(LIBUUID_LIBRARIES uuid) +#FIND_LIBRARY(LIBEVENT libevent) FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu NO_DEFAULT_PATH) FIND_LIBRARY(CPPKAFKA cppkafka /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(PULSAR pulsar /usr/lib NO_DEFAULT_PATH) -FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) +#FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../include NO_DEFAULT_PATH) -link_libraries(${RDKAFKA} ${CPPKAFKA} ${OPENVSWITCH} ${PULSAR}) +#link_libraries(${RDKAFKA} ${CPPKAFKA} ${OPENVSWITCH} ${PULSAR}) +link_libraries(${RDKAFKA} ${CPPKAFKA} ${PULSAR}) link_libraries(/usr/lib/x86_64-linux-gnu/libuuid.so) -include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${OPENVSWITCH_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR}) +link_libraries(/usr/lib/x86_64-linux-gnu/libevent_pthreads.so) +link_libraries(/usr/lib/x86_64-linux-gnu/libpthread.so) +link_libraries(/root/lfu/code/openvswitch-2.9.8/lib/.libs/libopenvswitch.a) +#include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${OPENVSWITCH_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) +include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/proto3) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/grpc) @@ -52,12 +92,15 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) add_library(AlcorControlAgentLib STATIC ${SOURCES}) +target_link_libraries(AlcorControlAgentLib event) #Libevent linking is '-levent', thus linked lib is 'event' in the cmd +target_link_libraries(AlcorControlAgentLib ssl) +target_link_libraries(AlcorControlAgentLib crypto) +target_link_libraries(AlcorControlAgentLib rt) add_executable(AlcorControlAgent aca_main.cpp) target_link_libraries(AlcorControlAgent cppkafka) target_link_libraries(AlcorControlAgent rdkafka) target_link_libraries(AlcorControlAgent pulsar) -target_link_libraries(AlcorControlAgent openvswitch) target_link_libraries(AlcorControlAgent AlcorControlAgentLib) target_link_libraries(AlcorControlAgent proto) target_link_libraries(AlcorControlAgent grpc) diff --git a/src/aca_main.cpp b/src/aca_main.cpp index f4c5330d..1b8a9563 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -18,8 +18,17 @@ #include "aca_message_pulsar_consumer.h" #include "aca_grpc.h" #include "aca_grpc_client.h" + +#undef UNUSED +#include "of_controller.h" #include "aca_ovs_l2_programmer.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP #include "aca_ovs_control.h" + #include "goalstateprovisioner.grpc.pb.h" #include #include /* for getopt */ @@ -59,6 +68,10 @@ string g_ofctl_options = EMPTY_STRING; string g_ncm_address = EMPTY_STRING; string g_ncm_port = EMPTY_STRING; +OFController *g_ovs_ctrl = NULL; +string g_ovs_ctrl_address = "127.0.0.1"; +int g_ovs_ctrl_port = 1234; + // total time for execute_system_command in microseconds std::atomic_ulong g_total_execute_system_time(0); // total time for execute_ovsdb_command in microseconds @@ -145,6 +158,16 @@ static void aca_cleanup() } else { ACA_LOG_ERROR("%s", "Unable to call delete, grpc client thread pointer is null.\n"); } + + if (g_ovs_ctrl != NULL) { + g_ovs_ctrl->stop(); + delete g_ovs_ctrl; + g_ovs_ctrl = NULL; + ACA_LOG_INFO("%s", "Cleaned up ovs controller.\n"); + } else { + ACA_LOG_INFO("%s", "Unable to clean up ovs controller, since it is null.\n"); + } + ACA_LOG_CLOSE(); } @@ -263,6 +286,20 @@ int main(int argc, char *argv[]) aca_cleanup(); return rc; } + + // start ovs server and point br-int/br-tun's controller to local ovs server + std::unordered_map switch_dpid_map = + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_ovs_bridge_mapping(); + + // set bridge controller will clean up flows + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_controller(g_ovs_ctrl_address, g_ovs_ctrl_port); + + // then add default ovs flows + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_default_flows(); + + g_ovs_ctrl = new OFController(switch_dpid_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); + g_ovs_ctrl->start(); + // monitor br-int for dhcp request message ovs_monitor_brint_thread = new thread(bind(&ACA_OVS_Control::monitor, diff --git a/src/net_config/aca_net_config.cpp b/src/net_config/aca_net_config.cpp index c4908b4f..45eabdec 100644 --- a/src/net_config/aca_net_config.cpp +++ b/src/net_config/aca_net_config.cpp @@ -16,6 +16,9 @@ #include "aca_util.h" #include "aca_config.h" #include "aca_net_config.h" + +#include +#include #include using namespace std; @@ -340,4 +343,32 @@ int Aca_Net_Config::execute_system_command(string cmd_string, ulong &culminative return rc; } +std::string Aca_Net_Config::execute_system_command_with_return(string cmd_string) +{ + char buffer[128]; + std::string result = ""; + + FILE* pipe = popen(cmd_string.c_str(), "r"); + if (!pipe) + { + ACA_LOG_ERROR("Aca_Net_Config::execute_system_command_with_return - failed to read output from popen\n"); + } + + try + { + while (fgets(buffer, sizeof buffer, pipe) != NULL) + { + result += buffer; + } + } + catch (...) + { + pclose(pipe); + ACA_LOG_ERROR("Aca_Net_Config::execute_system_command_with_return - failed to pclose cmd pipe\n"); + } + pclose(pipe); + + return result; +} + } // namespace aca_net_config diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index 44a97758..33655d8b 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -210,30 +210,6 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() "-- set interface patch-int type=patch options:peer=patch-tun", not_care_culminative_time, overall_rc); - // adding default flows - // details at: https://github.com/futurewei-cloud/alcor-control-agent/wiki/Openflow-Tables-Explain - - execute_openflow_command("add-flow br-tun \"table=0,priority=50,arp,arp_op=1, actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=20,priority=1 actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=52,priority=1 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - execute_ovsdb_command( string("--may-exist add-port br-tun vxlan-generic -- set interface vxlan-generic ofport_request=") + VXLAN_GENERIC_OUTPORT_NUMBER + @@ -274,6 +250,120 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() return overall_rc; } +int ACA_OVS_L2_Programmer::setup_ovs_default_flows() +{ + // adding default flows + // details at: https://github.com/futurewei-cloud/alcor-control-agent/wiki/Openflow-Tables-Explain + int overall_rc = EXIT_SUCCESS; + ulong not_care_culminative_time; + + execute_openflow_command("add-flow br-tun \"table=0,priority=50,arp,arp_op=1, actions=CONTROLLER\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=20,priority=1 actions=CONTROLLER\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=52,priority=1 actions=resubmit(,20)\"", + not_care_culminative_time, overall_rc); + + execute_openflow_command("add-flow br-tun \"table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)\"", + not_care_culminative_time, overall_rc); + + return overall_rc; +} + +int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port) +{ + int rc = EXIT_SUCCESS; + + const string ctrler_endpoint = " tcp:" + ctrler_ip + ":" + to_string(ctrler_port); + const string br_int_str = "br-int"; + const string br_tun_str = "br-tun"; + const string setup_br_int_cmd = "set-controller " + br_int_str + ctrler_endpoint; + const string setup_br_tun_cmd = "set-controller " + br_tun_str + ctrler_endpoint; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::setup_ovs_controller ---> Entering\n"); + auto ovsdb_client_start = chrono::steady_clock::now(); + + string br_int_cmd_string = "ovs-vsctl " + setup_br_int_cmd; + rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(br_int_cmd_string); + if (rc != EXIT_SUCCESS) { + ACA_LOG_ERROR("ACA_OVS_L2_Programmer::setup_ovs_controller - failed to set br-int controller\n"); + } + + string br_tun_cmd_string = "ovs-vsctl " + setup_br_tun_cmd; + rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(br_tun_cmd_string); + if (rc != EXIT_SUCCESS) { + ACA_LOG_ERROR("ACA_OVS_L2_Programmer::setup_ovs_controller - failed to set br-tun controller\n"); + } + + auto ovsdb_client_end = chrono::steady_clock::now(); + + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::setup_ovs_controller - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::setup_ovs_controller <--- Exiting\n"); + + return rc; +} + +std::unordered_map ACA_OVS_L2_Programmer::get_ovs_bridge_mapping() +{ + const string br_int_str = "br-int"; + const string br_tun_str = "br-tun"; + const string get_br_int_dpid = "get Bridge " + br_int_str + " datapath_id"; + const string get_br_tun_dpid = "get Bridge " + br_tun_str + " datapath_id"; + std::unordered_map switch_dpid_map; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::get_ovs_bridge_mapping ---> Entering\n"); + auto ovsdb_client_start = chrono::steady_clock::now(); + + string br_int_cmd_string = "ovs-vsctl " + get_br_int_dpid; + // raw string output format is like a hex string "00003af45ed7aa45" + string br_int_dpid_raw = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(br_int_cmd_string); + // trim the (") symbol at the start and the end to get 00003af45ed7aa45, and then convert to decimal + uint64_t br_int_dpid = std::stoul(br_int_dpid_raw.substr(1, br_int_dpid_raw.length() - 3), nullptr, 16); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - adding %ld - %s mapping to switch_dpid_map\n", br_int_dpid, br_int_str.c_str()); + switch_dpid_map[br_int_dpid] = br_int_str; + + string br_tun_cmd_string = "ovs-vsctl " + get_br_tun_dpid; + string br_tun_dpid_raw = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(br_tun_cmd_string); + uint64_t br_tun_dpid = std::stoul(br_tun_dpid_raw.substr(1, br_tun_dpid_raw.length() - 3), nullptr, 16); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - adding %ld - %s mapping to switch_dpid_map\n", br_tun_dpid, br_tun_str.c_str()); + switch_dpid_map[br_tun_dpid] = br_tun_str; + + auto ovsdb_client_end = chrono::steady_clock::now(); + + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping <--- Exiting\n"); + + return switch_dpid_map; +} + int ACA_OVS_L2_Programmer::create_port(const string vpc_id, const string port_name, const string virtual_ip, const string virtual_mac, uint tunnel_id, ulong &culminative_time) diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index eb7a3b5e..87900edd 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -190,6 +190,7 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, "->tun_dst,output:" + VXLAN_GENERIC_OUTPORT_NUMBER; std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); + /* overall_rc = ACA_OVS_Control::get_instance().add_flow( "br-tun", (match_string + action_string).c_str()); std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); @@ -201,6 +202,9 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, if (overall_rc != EXIT_SUCCESS) { ACA_LOG_ERROR("%s", "Failed to add L2 neighbor rule\n"); }; + */ + + // create arp entry in arp responder for the l2 neighbor stArpCfg.mac_address = virtual_mac; diff --git a/src/ovs/libfluid-base/OFClient.cc b/src/ovs/libfluid-base/OFClient.cc new file mode 100644 index 00000000..085d34bf --- /dev/null +++ b/src/ovs/libfluid-base/OFClient.cc @@ -0,0 +1,66 @@ +#include +#include + +#include "libfluid-base/OFClient.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/OFConnection.hh" +#include "libfluid-base/OFServer.hh" +#include "libfluid-base/base/of.hh" + +namespace fluid_base { + +OFClient::OFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure, + const struct OFServerSettings ofsc) : + BaseOFClient(addr, domainsocket, port, secure), + OFConnectionProcessor(this) {} + +OFClient::~OFClient() {} + +bool OFClient::start(bool block) { + return BaseOFClient::start(block); +} + +void OFClient::stop() { + if (conn) { + conn->close(); + } + // Stop BaseOFClient + BaseOFClient::stop(); +} + +void OFClient::set_config(OFServerSettings ofsc) { + OFConnectionProcessor::set_config(ofsc); +} + +void OFClient::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + OFConnectionProcessor::base_message_callback(c, data, len); +} + +void OFClient::free_data(void* data) { + BaseOFClient::free_data(data); +} + +void OFClient::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + OFConnectionProcessor::base_connection_callback(c, event_type); + if (event_type == BaseOFConnection::EVENT_CLOSED) { + // reconnect + if (!this->connect()) { + fprintf(stderr, "OFClient reconnect failed"); + } else { + fprintf(stderr, "OFClient reconnect success"); + } + } +} + +void OFClient::on_new_conn(OFConnection* cc) { + if (conn) { + conn->close(); + } + conn.reset(cc); +} +} // namespace fluid_base diff --git a/src/ovs/libfluid-base/OFConnection.cc b/src/ovs/libfluid-base/OFConnection.cc new file mode 100644 index 00000000..1239e441 --- /dev/null +++ b/src/ovs/libfluid-base/OFConnection.cc @@ -0,0 +1,86 @@ +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/OFConnection.hh" + +namespace fluid_base { + +OFConnection::OFConnection(BaseOFConnection* c, OFHandler* ofhandler) { + this->ofhandler = ofhandler; + this->conn = c; + this->conn->set_manager(this); + this->id = c->get_id(); + this->peer_address = c->get_peer_address(); + this->set_state(STATE_HANDSHAKE); + this->set_alive(true); + this->set_version(0); + this->application_data = NULL; +} + +int OFConnection::get_id() { + return this->id; +} + +std::string OFConnection::get_peer_address() { + return this->peer_address; +} + +bool OFConnection::is_alive() { + return this->alive; +} + +void OFConnection::set_alive(bool alive) { + this->alive = alive; +} + +uint8_t OFConnection::get_state() { + return state; +} + +void OFConnection::set_state(OFConnection::State state) { + this->state = state; +} + +uint8_t OFConnection::get_version() { + return this->version; +} + +void OFConnection::set_version(uint8_t version) { + this->version = version; +} + +OFHandler* OFConnection::get_ofhandler() { + return this->ofhandler; +} + +void OFConnection::send(void* data, size_t len) { + if (this->conn != NULL) + this->conn->send((uint8_t*) data, len); +} + +void OFConnection::add_timed_callback(void* (*cb)(void*), + int interval, + void* arg) { + if (this->conn != NULL) + this->conn->add_timed_callback(cb, interval, arg); +} + +void* OFConnection::get_application_data() { + return this->application_data; +} + +void OFConnection::set_application_data(void* data) { + this->application_data = data; +} + +void OFConnection::close() { + // Don't close twice + if (this->conn == NULL) + return; + + set_state(STATE_DOWN); + // Close the BaseOFConnection. This will trigger + // BaseOFHandler::base_connection_callback. Then BaseOFServer will take + // care of freeing it for us, so we can lose track of it. + this->conn->close(); + this->conn = NULL; +} +} diff --git a/src/ovs/libfluid-base/OFServer.cc b/src/ovs/libfluid-base/OFServer.cc new file mode 100644 index 00000000..f7c59702 --- /dev/null +++ b/src/ovs/libfluid-base/OFServer.cc @@ -0,0 +1,270 @@ +#include +#include + +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/OFConnection.hh" +#include "libfluid-base/OFServer.hh" +#include "libfluid-base/base/of.hh" + +namespace fluid_base { +OFConnectionProcessor::OFConnectionProcessor(OFHandler* h) : _handler(h) {} + +void OFConnectionProcessor::set_config(OFServerSettings ofsc) { + this->ofsc = ofsc; +} + +void OFConnectionProcessor::free_data(void* data) { + _handler->free_data(data); +} + +OFServer::OFServer( + const char* address, + const int port, + const int nthreads, + const bool secure, + const OFServerSettings ofsc) : + BaseOFServer(address, port, nthreads, secure),OFConnectionProcessor(this) { + pthread_mutex_init(&ofconnections_lock, NULL); + this->set_config(ofsc); +} + +OFServer::~OFServer() { + this->lock_ofconnections(); + while (!this->ofconnections.empty()) { + OFConnection* ofconn = this->ofconnections.begin()->second; + this->ofconnections.erase(this->ofconnections.begin()); + delete ofconn; + } + this->ofconnections.clear(); + this->unlock_ofconnections(); +} + +bool OFServer::start(bool block) { + return BaseOFServer::start(block); +} + +void OFServer::stop() { + // Close all connections + this->lock_ofconnections(); + for (std::map::iterator it = this->ofconnections.begin(); + it != this->ofconnections.end(); + it++) { + it->second->close(); + } + this->unlock_ofconnections(); + + // Stop BaseOFServer + BaseOFServer::stop(); +} + +OFConnection* OFServer::get_ofconnection(int id) { + this->lock_ofconnections(); + OFConnection* cc = ofconnections[id]; + this->unlock_ofconnections(); + return cc; +} + +void OFServer::set_config(OFServerSettings ofsc) { + this->ofsc = ofsc; + OFConnectionProcessor::set_config(ofsc); +} + +static uint32_t version_bitmap_from_version(uint8_t ofp_version) { + return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1; +} + +void OFServer::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + OFConnectionProcessor::base_message_callback(c, data, len); +} + +void OFConnectionProcessor::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + uint8_t version = ((uint8_t*) data)[0]; + uint8_t type = ((uint8_t*) data)[1]; + OFConnection* cc = (OFConnection*) c->get_manager(); + + // We trust that the other end is using the negotiated protocol version + // after the handshake is done. Should we? + + // Should we only answer echo requests after a features reply? The + // specification isn't clear about that, so we answer whenever an echo + // request arrives. + + // Handle echo requests + if (type == OFPT_ECHO_REQUEST) { + // Just change the type and send back + ((uint8_t*) data)[1] = OFPT_ECHO_REPLY; + c->send(data, ntohs(((uint16_t*) data)[1])); + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle hello messages + if (ofsc.handshake() and type == OFPT_HELLO) { + + uint32_t client_supported_versions; + + if (ofsc.use_hello_elements() && + len > 8 && + ntohs(((uint16_t*) data)[4]) == OFPHET_VERSIONBITMAP && + ntohs(((uint16_t*) data)[5]) >= 8) { + client_supported_versions = ntohl(((uint32_t*) data)[3]); + } + else { + client_supported_versions = version_bitmap_from_version(version); + } + + if (*this->ofsc.supported_versions() & client_supported_versions) { + struct ofp_fluid_header msg; + //msg.version = ((uint8_t*) data)[0]; + msg.version = this->ofsc.max_supported_version(); + msg.type = OFPT_FEATURES_REQUEST; + msg.length = htons(8); + msg.xid = ((uint32_t*) data)[1]; + c->send(&msg, 8); + } + else { + struct ofp_fluid_error_msg msg; + msg.header.version = version; + msg.header.type = OFPT_ERROR; + msg.header.length = htons(12); + msg.header.xid = ((uint32_t*) data)[1]; + msg.type = htons(OFPET_HELLO_FAILED); + msg.code = htons(OFPHFC_INCOMPATIBLE); + cc->send(&msg, 12); + + cc->close(); + cc->set_state(OFConnection::STATE_FAILED); + _handler->connection_callback(cc, OFConnection::EVENT_FAILED_NEGOTIATION); + } + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle echo replies (by registering them) + if (ofsc.liveness_check() and type == OFPT_ECHO_REPLY) { + if (ntohl(((uint32_t*) data)[1]) == ECHO_XID) { + cc->set_alive(true); + } + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle feature replies + if (ofsc.handshake() and type == OFPT_FEATURES_REPLY) { + cc->set_version(((uint8_t*) data)[0]); + cc->set_state(OFConnection::STATE_RUNNING); + if (ofsc.liveness_check()) + c->add_timed_callback(send_echo, ofsc.echo_interval() * 1000, cc); + _handler->connection_callback(cc, OFConnection::EVENT_ESTABLISHED); + + goto dispatch; + } + + goto dispatch; + + // Dispatch a message to the user callback and goto done + dispatch: + _handler->message_callback(cc, type, data, len); + if (this->ofsc.keep_data_ownership()) + this->free_data(data); + return; + + // Free the message (if necessary) and return + done: + this->free_data(data); + return; +} + +void OFServer::free_data(void* data) { + BaseOFServer::free_data(data); +} + +void OFServer::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + OFConnectionProcessor::base_connection_callback(c, event_type); +} +void OFConnectionProcessor::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + // If the connection was closed, destroy it + // (BaseOFServer::base_connection_callback will do it for us). + // There's no need to notify the user, since a BaseOFConnection::EVENT_DOWN + // event already means a BaseOFConnection::EVENT_CLOSED will happen and + // nothing should be expected from the connection anymore. + if (event_type == BaseOFConnection::EVENT_CLOSED) { + delete c; + // TODO: delete the OFConnection? Currently we keep track of all + // connections that have been started and their status. When a + // connection is closed, pretty much all of its data is freed already, + // so this isn't a big overhead, and so we keep the references to old + // connections for the user. + return; + } + + if (event_type == BaseOFConnection::EVENT_UP) { + if (ofsc.handshake()) { + int msglen = 8; + if (ofsc.use_hello_elements()) { + msglen = 16; + } + + uint8_t msg[msglen]; + + struct ofp_hello* hello = (struct ofp_hello*) &msg; + hello->header.version = this->ofsc.max_supported_version(); + hello->header.type = OFPT_HELLO; + hello->header.length = htons(msglen); + hello->header.xid = htonl(HELLO_XID); + + if (this->ofsc.max_supported_version() >= 4 && ofsc.use_hello_elements()) { + struct ofp_hello_elem_versionbitmap* elm = + (struct ofp_hello_elem_versionbitmap*) (&msg[8]); + elm->type = htons(OFPHET_VERSIONBITMAP); + elm->length = htons(8); + + uint32_t* bitmaps = (uint32_t*) (&msg[12]); + *bitmaps = htonl(*this->ofsc.supported_versions()); + } + + c->send(&msg, msglen); + } + + OFConnection* cc = new OFConnection(c, _handler); + on_new_conn(cc); + _handler->connection_callback(cc, OFConnection::EVENT_STARTED); + } + else if (event_type == BaseOFConnection::EVENT_DOWN) { + auto cc = static_cast(c->get_manager()); + _handler->connection_callback(cc, OFConnection::EVENT_CLOSED); + cc->close(); + } +} + +void OFServer::on_new_conn(OFConnection* cc) { + lock_ofconnections(); + ofconnections[cc->get_id()] = cc; + unlock_ofconnections(); +} + +/** This method will periodically send echo requests. */ +void* OFConnectionProcessor::send_echo(void* arg) { + OFConnection* cc = static_cast(arg); + + if (!cc->is_alive()) { + cc->close(); + cc->get_ofhandler()->connection_callback(cc, OFConnection::EVENT_DEAD); + return NULL; + } + + uint8_t msg[8]; + memset((void*) msg, 0, 8); + msg[0] = (uint8_t) cc->get_version(); + msg[1] = OFPT_ECHO_REQUEST; + ((uint16_t*) msg)[1] = htons(8); + ((uint32_t*) msg)[1] = htonl(ECHO_XID); + + cc->set_alive(false); + cc->send(msg, 8); + + return NULL; +} + +} diff --git a/src/ovs/libfluid-base/OFServerSettings.cc b/src/ovs/libfluid-base/OFServerSettings.cc new file mode 100644 index 00000000..0e6cbaff --- /dev/null +++ b/src/ovs/libfluid-base/OFServerSettings.cc @@ -0,0 +1,108 @@ +#include "libfluid-base/OFServerSettings.hh" + +namespace fluid_base { + +OFServerSettings::OFServerSettings() { + this->_supported_versions = 0; + this->add_version(1); + this->version_set_by_hand = false; + this->echo_interval(15); + this->liveness_check(true); + this->handshake(true); + this->dispatch_all_messages(false); + this->use_hello_elements(false); + this->keep_data_ownership(true); +} + +OFServerSettings& OFServerSettings::supported_version(const uint8_t version) { + // If the user sets the version by hand, then all supported versions must + // be explicitly declared. + if (not this->version_set_by_hand) { + this->version_set_by_hand = true; + this->_supported_versions = 0; + } + this->add_version(version); + return *this; +} + +void OFServerSettings::add_version(const uint8_t version) { + this->_supported_versions |= (1 << version); + + unsigned int x = 0; + this->_max_supported_version = 0; + for (x = (unsigned int) this->_supported_versions; + x > 0; + x = x >> 1, this->_max_supported_version++); + this->_max_supported_version--; +} + +uint32_t* OFServerSettings::supported_versions() { + // We return a pointer because an OFServerSettings object is supposed to + // be exclusively user by an OFServer instance which has a copy of it. + + // TODO: since this->_supported_versions is just an uint32_t, we can only + // support OpenFlow versions lower than 31. It might be a problem some day, + // so it would be nice to change the implementation to a proper uint32_t + // array. + return &this->_supported_versions; +} + +uint8_t OFServerSettings::max_supported_version() { + return this->_max_supported_version; +} + +OFServerSettings& OFServerSettings::echo_interval(const int ei) { + this->_echo_interval = ei; + return *this; +} + +int OFServerSettings::echo_interval() { + return this->_echo_interval; +} + +OFServerSettings& OFServerSettings::liveness_check(const bool liveness_check) { + this->_liveness_check = liveness_check; + return *this; +} + +bool OFServerSettings::liveness_check() { + return this->_liveness_check; +} + +OFServerSettings& OFServerSettings::handshake(const bool handshake) { + this->_handshake = handshake; + return *this; +} + +bool OFServerSettings::handshake() { + return this->_handshake; +} + +OFServerSettings& OFServerSettings::dispatch_all_messages(const bool dispatch_all_messages) { + this->_dispatch_all_messages = dispatch_all_messages; + return *this; +} + +bool OFServerSettings::dispatch_all_messages() { + return this->_dispatch_all_messages; +} + +bool OFServerSettings::use_hello_elements() { + return this->_use_hello_elements; +} + +OFServerSettings& OFServerSettings::use_hello_elements(const bool use_hello_elements) { + this->_use_hello_elements = use_hello_elements; + return *this; +} + +bool OFServerSettings::keep_data_ownership() { + return this->_keep_data_ownership; +} + +OFServerSettings& OFServerSettings::keep_data_ownership(const bool keep_data_ownership) { + this->_keep_data_ownership = keep_data_ownership; + return *this; +} + +} diff --git a/src/ovs/libfluid-base/TLS.cc b/src/ovs/libfluid-base/TLS.cc new file mode 100644 index 00000000..c4211536 --- /dev/null +++ b/src/ovs/libfluid-base/TLS.cc @@ -0,0 +1,99 @@ +#include "libfluid-base/base/config.h" + +#if defined(HAVE_TLS) + +#include +#include +#include +#include +#include +#include + +#include + +#include "libfluid-base/TLS.hh" + +namespace fluid_base { + +void* tls_obj = NULL; +pthread_mutex_t* ssl_locks; +int ssl_num_locks; + +static unsigned long get_thread_id_cb(void) { + return (unsigned long) pthread_self(); +} + +static void thread_lock_cb(int mode, int which, const char * f, int l) { + if (which < ssl_num_locks) { + if (mode & CRYPTO_LOCK) { + pthread_mutex_lock(&(ssl_locks[which])); + } else { + pthread_mutex_unlock(&(ssl_locks[which])); + } + } +} + +// TODO: make these function idempotent + +void libfluid_tls_init(const char* cert, const char* privkey, const char* trustedcert) { + int i; + SSL_CTX *server_ctx; + + tls_obj = NULL; + + ssl_num_locks = CRYPTO_num_locks(); + ssl_locks = (pthread_mutex_t*) malloc(ssl_num_locks * sizeof(pthread_mutex_t)); + if (ssl_locks == NULL) + return; + + for (i = 0; i < ssl_num_locks; i++) { + pthread_mutex_init(&(ssl_locks[i]), NULL); + } + + // TODO: change this to the CRYPTO_THREADID family of functions to aid + // portability. While this will work on Linux, it is deprecated and should + // be changed. + CRYPTO_set_id_callback(get_thread_id_cb); + CRYPTO_set_locking_callback(thread_lock_cb); + + /* Initialize OpenSSL */ + SSL_load_error_strings(); + SSL_library_init(); + + /* Stop if there's no entropy */ + if (!RAND_poll()) + return; + + server_ctx = SSL_CTX_new(SSLv23_server_method()); + + if (!SSL_CTX_load_verify_locations(server_ctx, trustedcert, NULL)) { + fprintf(stderr, "Error loading verification CA certificate.\n"); + return; + } + SSL_CTX_set_verify(server_ctx, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + + if (!SSL_CTX_use_certificate_chain_file(server_ctx, cert)) { + fprintf(stderr, "Error loading certificate.\n"); + return; + } + + if (!SSL_CTX_use_PrivateKey_file(server_ctx, privkey, SSL_FILETYPE_PEM)) { + fprintf(stderr, "Error loading private key.\n"); + return; + } + + tls_obj = server_ctx; +} + +void libfluid_tls_clear() { + // TODO: investigate how to free the memory (~84k) that is still reachable + // after this function runs. + if (tls_obj != NULL) { + SSL_CTX_free((SSL_CTX*) tls_obj); + } +} + +} + +#endif diff --git a/src/ovs/libfluid-base/base/BaseOFClient.cc b/src/ovs/libfluid-base/base/BaseOFClient.cc new file mode 100644 index 00000000..d29a68cf --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFClient.cc @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "libfluid-base/base/BaseOFClient.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/EventLoop.hh" +#include "libfluid-base/TLS.hh" + +#include +#include + +namespace fluid_base { +#define OVS_CONN_SELECT_TIMEOUT 20 + +static bool evthread_use_pthreads_called = false; + +class BaseOFClient::LibEventBaseOFClient { +private: + friend class BaseOFClient; + + static void conn_cb(evutil_socket_t fd, const std::string &peer_address, void *arg); + static void conn_error_cb(void *arg); +}; + +BaseOFClient::BaseOFClient(const std::string &addr, const bool d, const int p, const bool s) : + address(addr), + domainsocket(d), + port(p), + secure(s), + blocking(false), + evloop(nullptr), + evthread(0), + nconn(0), + m_implementation(nullptr) { + // Prepare libevent for threads + // This will leave a small, insignificant leak for us. + // See: http://archives.seul.org/libevent/users/Jul-2011/msg00028.html + if (!evthread_use_pthreads_called) { + evthread_use_pthreads(); + evthread_use_pthreads_called = true; + } + + // Ignore SIGPIPE so it becomes an EPIPE + signal(SIGPIPE, SIG_IGN); + + m_implementation = new BaseOFClient::LibEventBaseOFClient; + +#if defined(HAVE_TLS) + if (this->secure && tls_obj == NULL) { + fprintf(stderr, "To establish secure connections, call libfluid_tls_init first.\n"); + } +#endif +} + +BaseOFClient::~BaseOFClient() { + delete this->m_implementation; + delete this->evloop; +} + +bool BaseOFClient::start(bool block) { + this->blocking = block; + + this->evloop = new EventLoop(0); + + // connect to ovs-db server and assign it to the event loop + if (!this->connect()) { + return false; + } + if (this->secure) { + fprintf(stderr, "Secure "); + } + fprintf(stderr, "ovs client started (%s)\n", this->address.c_str()); + + // start a new thread for event loop + pthread_create(&evthread, NULL, EventLoop::thread_adapter, evloop); + + return true; +} + +void BaseOFClient::stop() { + // ask event loop to stop + if (evloop) { + evloop->stop(); + } + + // wait for event loop thread to finish + if (evthread > 0) { + pthread_join(evthread, NULL); + } +} + +bool BaseOFClient::connect() { + int status = 0; + evutil_socket_t fd; + + if (this->domainsocket) { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + } else { + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } + + if (fd < 0) { + fprintf(stderr, "Could not create socket to %s\n", this->address.c_str()); + close(fd); + + return false; + } + + // if connect is non-blocking + if (!this->blocking) { + // set non-blocking mode socket flags + int flags = fcntl(fd, F_GETFL, 0); + int nonblocking_flags = flags | O_NONBLOCK; + + // set fd as non-blocking + fcntl(fd, F_SETFL, nonblocking_flags); + + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status == 0) { + // connect successfully immediately + fcntl(fd, F_SETFL, flags); + } else { + if (errno != EINPROGRESS) { + // if it did not connect immediately and errno != EINPROGRESS, it means there is + // error + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way, errno != " + "EINPROGRESS but = %d\n", + this->address.c_str(), + errno); + close(fd); + + return false; + } else { + fd_set read_fds; + fd_set write_fds; + struct timeval select_timeout; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_SET(fd, &read_fds); + FD_SET(fd, &write_fds); + + select_timeout.tv_sec = OVS_CONN_SELECT_TIMEOUT; + select_timeout.tv_usec = 0; + + status = ::select(fd + 1, &read_fds, &write_fds, NULL, &select_timeout); + + if (status <= 0) { + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way, select " + "timeout or error %d\n", + this->address.c_str(), + status); + close(fd); + + return false; + } + + if (FD_ISSET(fd, &write_fds)) { + if (FD_ISSET(fd, &read_fds)) { + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect( + fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect( + fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status != 0) { + int error = 0; + socklen_t len = sizeof(errno); + + // use getsockopt() to get fd error + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + fprintf(stderr, + "Could not get socket option of %s\n", + this->address.c_str()); + close(fd); + + return false; + } + + if (error != EISCONN) { + fprintf(stderr, + "Could not connect to %s and error != EISCONN\n", + this->address.c_str()); + close(fd); + + return false; + } + } + } + } else { + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way\n", + this->address.c_str()); + close(fd); + + return false; + } + + // connect successfully after select + fcntl(fd, F_SETFL, flags); + } + } + } else { + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status < 0) { + fprintf(stderr, + "Could not connect to openflow server %s, status is %d\n", + this->address.c_str(), + status); + close(fd); + + return false; + } + } + + // make the socket non-blocking + evutil_make_socket_nonblocking(fd); + + // create OvsdbConnection with connected socket fd and evloop + this->m_implementation->conn_cb(fd, address, this); + + return true; +} + +void BaseOFClient::free_data(void *data) { + BaseOFConnection::free_data(data); +} + +/* Internal libevent callbacks */ +void BaseOFClient::LibEventBaseOFClient::conn_cb( + evutil_socket_t fd, + const std::string &peer_address, + void *arg) { + auto client = static_cast(arg); + int id = client->nconn++; + + BaseOFConnection *c = + new BaseOFConnection(id, client, client->evloop, fd, client->secure, peer_address); +} + +void BaseOFClient::LibEventBaseOFClient::conn_error_cb(void *arg) { + int err = EVUTIL_SOCKET_ERROR(); + fprintf(stderr, + "BaseOFClient connection error (%d: %s)", + err, + evutil_socket_error_to_string(err)); +} + +} // namespace fluid_base diff --git a/src/ovs/libfluid-base/base/BaseOFConnection.cc b/src/ovs/libfluid-base/base/BaseOFConnection.cc new file mode 100644 index 00000000..de3b98fe --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFConnection.cc @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "libfluid-base/base/config.h" +#if defined(HAVE_TLS) +#include +#include +#include +#include +#include "libfluid-base/TLS.hh" +#endif + +#include "libfluid-base/base/BaseOFConnection.hh" + +namespace fluid_base { + +#define OF_HEADER_LENGTH 8 + +/** An OFReadBuffer holds an OpenFlow message while it is being read and built. + +This class is for internal use (it was created to simplify BaseOFConnection), +and it assumes the user will respect the read limits and will always inform +about read data. +*/ +class BaseOFConnection::OFReadBuffer { + public: + /** Create an BaseOFConnection::OFReadBuffer. */ + OFReadBuffer(){ + clear(); + } + ~OFReadBuffer() { + if (data != NULL) + delete[] data; + } + + /** Get how many bytes should be read for this buffer. + + If the buffer is initialized (a complete OpenFlow header has been + read), it will return how many bytes of the message are still unread. + + If the buffer is unitialized (a complete OpenFlow header has not been + read), it will return how many bytes of the header still need to be + read. + */ + inline uint16_t get_read_len() { + if (init) + return this->len - this->pos; + else + return OF_HEADER_LENGTH - header_pos; + } + + /** Get a pointer to the position at which a read operation should put + the data. + */ + inline uint8_t* get_read_pos() { + if (init) + return this->data + this->pos; + else + return this->header + this->header_pos; + } + + /** Notify the buffer that a read operation was made and a given number + of bytes is read. This will initialize the buffer for reading a message + if a complete OpenFlow header was read. + + @param read how many bytes were read + */ + inline void read_notify(uint16_t read) { + if (init) + this->pos += read; + else { + this->header_pos += read; + if (this->header_pos == OF_HEADER_LENGTH) { + this->len = htons(*((uint16_t*) this->header + 1)); + this->data = new uint8_t[this->len]; + memcpy(this->data, this->header, OF_HEADER_LENGTH); + this->pos += OF_HEADER_LENGTH; + init = true; + } + } + } + + /** Check if there is a complete OpenFlow message in the buffer. */ + inline bool is_ready(void) { + return (this->len != 0) && (this->pos == this->len); + } + + /** Fetch the data if there is a completely read OpenFlow message in + the buffer. Return NULL otherwise. */ + inline void* get_data(void) { + return this->data; + } + + /** Return the length of the message being read in this buffer (in + bytes). It will return 0 if the OpenFlow header has not been fully + received yet. */ + inline int get_len() { + return this->len; + } + + /** Clear the buffer, making it ready to read new messages. + + @param delete_data destroy the dinamically allocated data + (false by default) + */ + inline void clear(bool delete_data = false) { + if (delete_data and data != NULL) { + delete[] data; + } + this->data = NULL; + this->init = false; + + memset(this->header, 0, OF_HEADER_LENGTH); + this->header_pos = 0; + + this->pos = 0; + this->len = 0; + } + + /** Free a pointer allocated by this buffer. */ + static void free_data(void* data) { + delete[] (uint8_t*) data; + } + + uint8_t* data; + bool init; + + uint8_t header[OF_HEADER_LENGTH]; + uint16_t header_pos; + + uint16_t pos; + uint16_t len; +}; + +class BaseOFConnection::LibEventBaseOFConnection { +private: + friend class BaseOFConnection; + + struct bufferevent* bev{nullptr}; + struct event* close_event{nullptr}; + + static void event_cb(struct bufferevent *bev, short events, void* arg); + static void timer_callback(evutil_socket_t fd, short what, void *arg); + static void read_cb(struct bufferevent *bev, void* arg); + static void close_cb(int fd, short which, void *arg); +}; + +BaseOFConnection::BaseOFConnection(int id, + BaseOFHandler* ofhandler, + EventLoop* evloop, + int fd, + bool secure, + std::string peer_address) { + this->id = id; + this->peer_address = peer_address; + // TODO: move event_base to BaseOFConnection::LibEventBaseOFConnection so + // we don't need to store this here + this->evloop = evloop; + this->buffer = new BaseOFConnection::OFReadBuffer(); + this->manager = NULL; + this->ofhandler = ofhandler; + this->m_implementation = new BaseOFConnection::LibEventBaseOFConnection; + + struct event_base* base = (struct event_base*) evloop->get_base(); + this->m_implementation->close_event = event_new(base, + -1, + EV_PERSIST, + BaseOFConnection::LibEventBaseOFConnection::close_cb, + this); + event_add(this->m_implementation->close_event, NULL); + + this->secure = false; + #if defined(HAVE_TLS) + if (secure) { + if (tls_obj != NULL) { + SSL_CTX* server_ctx = (SSL_CTX*) tls_obj; + SSL* client_ctx = SSL_new(server_ctx); + this->m_implementation->bev = bufferevent_openssl_socket_new(base, + fd, client_ctx, + BUFFEREVENT_SSL_ACCEPTING, + BEV_OPT_CLOSE_ON_FREE | + BEV_OPT_THREADSAFE); + this->secure = true; + } + else { + fprintf(stderr, "Establishing insecure connection.\nYou must call libfluid_tls_init first to establish secure connections.\n"); + secure = false; + } + } + #endif + if (!this->m_implementation->bev) { + if (secure) { + fprintf(stderr, "Establishing insecure connection.\nYou intend to establish secure connection in environment of HAVE_TLS==0.\n"); + } + + this->m_implementation->bev = bufferevent_socket_new(base, + fd, + BEV_OPT_CLOSE_ON_FREE | + BEV_OPT_THREADSAFE); + } + + notify_conn_cb(BaseOFConnection::EVENT_UP); + + bufferevent_setcb(this->m_implementation->bev, + BaseOFConnection::LibEventBaseOFConnection::read_cb, + NULL, + BaseOFConnection::LibEventBaseOFConnection::event_cb, + this); + bufferevent_enable(this->m_implementation->bev, EV_READ|EV_WRITE); +} + +BaseOFConnection::~BaseOFConnection() { + delete this->m_implementation; +} + +void BaseOFConnection::send(void* data, size_t len) { + bufferevent_write(this->m_implementation->bev, data, len); +} + +void BaseOFConnection::add_timed_callback(void* (*cb)(void*), int interval, void* arg) { + struct timeval tv = { interval / 1000, (interval % 1000) * 1000 }; + struct timed_callback* tc = new struct timed_callback; + tc->cb = cb; + tc->cb_arg = arg; + struct event_base* base = (struct event_base*) this->evloop->get_base(); + struct event* ev = event_new(base, + -1, + EV_PERSIST, + BaseOFConnection::LibEventBaseOFConnection::timer_callback, + tc); + tc->data = ev; + timed_callbacks.push_back(tc); + event_add(ev, &tv); +} + +void BaseOFConnection::set_manager(void* manager) { + this->manager = manager; +} + +void* BaseOFConnection::get_manager() { + return this->manager; +} + +int BaseOFConnection::get_id() { + return this->id; +} + +std::string BaseOFConnection::get_peer_address() { + return this->peer_address; +} + +void BaseOFConnection::close() { + event_active(this->m_implementation->close_event, EV_READ, 0); +} + +void BaseOFConnection::free_data(void* data) { + BaseOFConnection::OFReadBuffer::free_data(data); +} + +/* Private BaseOFConnection methods */ +void BaseOFConnection::notify_msg_cb(void* data, size_t n) { + ofhandler->base_message_callback(this, data, n); +} + +void BaseOFConnection::notify_conn_cb(BaseOFConnection::Event event_type) { + ofhandler->base_connection_callback(this, event_type); +} + +void BaseOFConnection::do_close() { + // Stop all timed callbacks + struct timed_callback* tc; + for(std::vector::iterator it = timed_callbacks.begin(); + it != timed_callbacks.end(); + it++) { + tc = *it; + event_del((struct event*) tc->data); + event_free((struct event*) tc->data); + delete tc; + } + + // Stop the events and delete the buffers + event_del(this->m_implementation->close_event); + event_free(this->m_implementation->close_event); + + // Workaround for a clean SSL shutdown. + // See: http://www.wangafu.net/~nickm/libevent-book/Ref6a_advanced_bufferevents.html + #if defined(HAVE_TLS) + if (this->secure) { + SSL *ctx = bufferevent_openssl_get_ssl(this->m_implementation->bev); + SSL_set_shutdown(ctx, SSL_RECEIVED_SHUTDOWN); + SSL_shutdown(ctx); + } + #endif + + bufferevent_free(this->m_implementation->bev); + delete this->buffer; + this->buffer = NULL; + + notify_conn_cb(BaseOFConnection::EVENT_CLOSED); +} + +/* libevent callbacks */ +void BaseOFConnection::LibEventBaseOFConnection::event_cb(struct bufferevent *bev, short events, void* arg) { + BaseOFConnection* c = static_cast(arg); + + if (events & BEV_EVENT_ERROR) + perror("Connection error"); + if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { + bufferevent_disable(bev, EV_READ|EV_WRITE); + c->notify_conn_cb(BaseOFConnection::EVENT_DOWN); + } +} + +void BaseOFConnection::LibEventBaseOFConnection::timer_callback(evutil_socket_t fd, short what, void *arg) { + struct BaseOFConnection::timed_callback* tc = static_cast(arg); + tc->cb(tc->cb_arg); +} + +void BaseOFConnection::LibEventBaseOFConnection::read_cb(struct bufferevent *bev, void* arg) { + BaseOFConnection* c = static_cast(arg); + + uint16_t len; + BaseOFConnection::OFReadBuffer* ofbuf = c->buffer; + + while (1) { + // Decide how much we should read + len = ofbuf->get_read_len(); + if (len <= 0) break; + + // Read the data and put it in the buffer + size_t read = bufferevent_read(bev, ofbuf->get_read_pos(), len); + if (read <= 0) break; else ofbuf->read_notify(read); + + // Check if the message is fully received and dispatch + if (ofbuf->is_ready()) { + void* data = ofbuf->get_data(); + size_t len = ofbuf->get_len(); + ofbuf->clear(); + c->notify_msg_cb(data, len); + } + } +} + +void BaseOFConnection::LibEventBaseOFConnection::close_cb(int fd, short which, void *arg) { + BaseOFConnection* c = static_cast(arg); + c->do_close(); +} + +} diff --git a/src/ovs/libfluid-base/base/BaseOFServer.cc b/src/ovs/libfluid-base/base/BaseOFServer.cc new file mode 100644 index 00000000..69e1944a --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFServer.cc @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/EventLoop.hh" +#include "libfluid-base/TLS.hh" + +#include +#include + +namespace fluid_base { + +static bool evthread_use_pthreads_called = false; + +class BaseOFServer::LibEventBaseOFServer { +private: + friend class BaseOFServer; + struct evconnlistener *listener; + static void conn_accept_cb(struct evconnlistener *listener, + evutil_socket_t fd, + struct sockaddr *address, + int socklen, + void *arg); + static void conn_accept_error_cb(struct evconnlistener *listener, + void* arg); +}; + +BaseOFServer::BaseOFServer(const char* address_, const int port, const int nthreads, bool secure) { + // Prepare libevent for threads + // This will leave a small, insignificant leak for us. + // See: http://archives.seul.org/libevent/users/Jul-2011/msg00028.html + if (!evthread_use_pthreads_called) { + evthread_use_pthreads(); + evthread_use_pthreads_called = true; + } + + // Ignore SIGPIPE so it becomes an EPIPE + signal(SIGPIPE, SIG_IGN); + + m_implementation = new BaseOFServer::LibEventBaseOFServer; + this->m_implementation->listener = NULL; + + this->nconn = 0; + + this->secure = secure; + + #if defined(HAVE_TLS) + if (this->secure && tls_obj == NULL) { + fprintf(stderr, "To establish secure connections, call libfluid_tls_init first.\n"); + } + #endif + + // Create event loops + // Threads will be created in BaseOFServer::start + this->nthreads = nthreads; + this->eventloops = new EventLoop*[nthreads]; + this->threads = new pthread_t[nthreads]; + memset(this->threads, 0, sizeof(pthread_t)*nthreads); + for (int i = 0; i < nthreads; i++) { + this->eventloops[i] = new EventLoop(i); + } + // The first event loop will be used for connections, so we move to the + // next one for the first connection + eventloop = 0; + if (nthreads > 1) + eventloop = 1; + + size_t address_len = strlen(address_) + 1; + this->address = new char[address_len]; + memcpy(this->address, address_, address_len); + snprintf(this->port, 6, "%d", port); +} + +BaseOFServer::~BaseOFServer() { + delete[] threads; + + if (this->m_implementation->listener != NULL) { + evconnlistener_free(this->m_implementation->listener); + this->m_implementation->listener = NULL; + } + + // Delete the event loops + for (int i = 0; i < nthreads; i++) { + delete eventloops[i]; + } + + delete[] eventloops; + + delete m_implementation; + + delete[] this->address; +} + +bool BaseOFServer::start(bool block) { + this->blocking = block; + + // Start listening for connections in the first event loop + if (not listen(eventloops[0])) + return false; + if (this->secure) + fprintf(stderr, "Secure "); + fprintf(stderr, "Server running (%s:%s)\n", this->address, this->port); + + // Start one thread for each event loop + // If we're blocking, the first event loop will run in the calling thread + for (int i = this->blocking? 1 : 0; i < nthreads; i++) { + pthread_create(&threads[i], + NULL, + EventLoop::thread_adapter, + eventloops[i]); + } + + // Start the first event loop in the calling thread if we're blocking + if (this->blocking) { + eventloops[0]->run(); + } + + return true; +} + +void BaseOFServer::stop() { + // Stop listening for new connections + if (m_implementation->listener != NULL) + evconnlistener_disable(m_implementation->listener); + + // Ask all event loops to stop + for (int i = 0; i < nthreads; i++) { + eventloops[i]->stop(); + } + + // Wait for all threads to finish (which will happen when the event loops + // stop running) + for (int i = this->blocking? 1 : 0; i < nthreads; i++) { + pthread_join(threads[i], NULL); + } +} + +bool BaseOFServer::listen(EventLoop* evloop) { + struct event_base *base = (struct event_base*) evloop->get_base();; + + // Hostname lookup + struct evutil_addrinfo hints; + struct evutil_addrinfo *result = NULL, *rp; + int err; + evutil_socket_t fd; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; + + err = evutil_getaddrinfo(this->address, this->port, &hints, &result); + if (err != 0) { + fprintf(stderr, "Error resolving '%s': %s\n", this->address, + evutil_gai_strerror(err)); + return false; + } + + int v = 1; + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); + if (fd == -1) + continue; + + if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) + break; + + close(fd); + } + + if (rp == NULL) { + fprintf(stderr, "Could not bind to '%s' (%s)\n", + this->address, strerror(errno)); + freeaddrinfo(result); + return false; + } + + freeaddrinfo(result); + + // Listen + evutil_make_socket_nonblocking(fd); + m_implementation->listener = evconnlistener_new(base, + m_implementation->conn_accept_cb, + this, + LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, + -1, + fd); + if (!m_implementation->listener) { + perror("Error creating connection listener"); + return false; + } + evconnlistener_set_error_cb(m_implementation->listener, m_implementation->conn_accept_error_cb); + + return true; +} + +EventLoop* BaseOFServer::choose_eventloop() { + EventLoop* selected_evloop = eventloops[eventloop]; + eventloop = (++eventloop) % nthreads; + return selected_evloop; +} + +void BaseOFServer::base_connection_callback(BaseOFConnection* conn, BaseOFConnection::Event event_type) { + if (event_type == BaseOFConnection::EVENT_CLOSED) + delete conn; +} + +void BaseOFServer::free_data(void* data) { + BaseOFConnection::free_data(data); +} + +static std::string get_in_addr(struct sockaddr *addr) +{ + const char* ret = NULL; + std::ostringstream sret; + + if (addr->sa_family == AF_INET) { + struct sockaddr_in* sa = (struct sockaddr_in*) addr; + + char peer[INET_ADDRSTRLEN]; + if (ret = evutil_inet_ntop(AF_INET, &sa->sin_addr, peer, sizeof(peer))) { + sret << ret << ':' << sa->sin_port; + } + } else if (addr->sa_family == AF_INET6) { + struct sockaddr_in6* sa = (struct sockaddr_in6*) addr; + + char peer[INET6_ADDRSTRLEN]; + if (ret = evutil_inet_ntop(AF_INET, &sa->sin6_addr, peer, sizeof(peer))) { + sret << '[' << ret << "]:" << sa->sin6_port; + } + } + + return sret.str(); +} + +/* Internal libevent callbacks */ +void BaseOFServer::LibEventBaseOFServer::conn_accept_cb(struct evconnlistener *listener, + evutil_socket_t fd, + struct sockaddr *address, + int socklen, + void *arg) { + + BaseOFServer* ofserver = static_cast(arg); + int id = ofserver->nconn++; + std::string saddr = get_in_addr(address); + BaseOFConnection* c = new BaseOFConnection(id, ofserver, ofserver->choose_eventloop(), fd, ofserver->secure, saddr); +} + +void BaseOFServer::LibEventBaseOFServer::conn_accept_error_cb(struct evconnlistener *listener, + void* arg) { + struct event_base *base = evconnlistener_get_base(listener); + int err = EVUTIL_SOCKET_ERROR(); + fprintf(stderr, "BaseOFServer error (%d :%s).", + err, evutil_socket_error_to_string(err)); +} + +} diff --git a/src/ovs/libfluid-base/base/EventLoop.cc b/src/ovs/libfluid-base/base/EventLoop.cc new file mode 100644 index 00000000..f676781d --- /dev/null +++ b/src/ovs/libfluid-base/base/EventLoop.cc @@ -0,0 +1,78 @@ +#include "libfluid-base/base/EventLoop.hh" +#include +#include + +namespace fluid_base { + +// Define our own value, since the stdint.h define doesn't work in C++ +#define OF_MAX_LEN 0xFFFF + +// See FIXME in EventLoop::EventLoop +//extern "C" void event_base_add_virtual(struct event_base *); +//extern "C" void event_base_del_virtual(struct event_base *); + +class EventLoop::LibEventEventLoop { +private: + friend class EventLoop; + struct event_base *base; +}; + +EventLoop::EventLoop(int id) { + this->id = id; + this->m_implementation = new EventLoop::LibEventEventLoop; + + this->m_implementation->base = event_base_new(); + + this->stopped = false; + if (!this->m_implementation->base) { + fprintf(stderr, "Error creating EventLoop %d\n", id); + exit(EXIT_FAILURE); + } + + /* FIXME: dirty hack warning! + We add a virtual event to prevent the loop from exiting when there are + no events. + + This fix is needed because libevent 2.0 doesn't have the flag + EVLOOP_NO_EXIT_ON_EMPTY. Version 2.1 fixes this, so this will have to + be changed in the future (to make it prettier and to avoid breaking + anything). + + See: + http://stackoverflow.com/questions/7645217/user-triggered-event-in-libevent + */ + //event_base_add_virtual(this->m_implementation->base); +} + +EventLoop::~EventLoop() { + event_base_free(this->m_implementation->base); + delete this->m_implementation; +} + +void EventLoop::run() { + // Only run if EventLoop::stop hasn't been called first + if (stopped) return; + + event_base_dispatch(this->m_implementation->base); + // See note in EventLoop::EventLoop. Here we disable the virtual event + // to guarantee that nothing blocks. + //event_base_del_virtual(this->m_implementation->base); + event_base_loop(this->m_implementation->base, EVLOOP_NO_EXIT_ON_EMPTY); +} + +void EventLoop::stop() { + // Prevent run from running if it's not started :) + this->stopped = true; + event_base_loopbreak(this->m_implementation->base); +} + +void* EventLoop::thread_adapter(void* arg) { + ((EventLoop*) arg)->run(); + return NULL; +} + +void* EventLoop::get_base() { + return this->m_implementation->base; +} + +} diff --git a/src/ovs/libfluid-msg/of10/of10action.cc b/src/ovs/libfluid-msg/of10/of10action.cc new file mode 100644 index 00000000..7ccee40d --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10action.cc @@ -0,0 +1,501 @@ +#include "libfluid-msg/of10/of10action.hh" +#include "libfluid-msg/of10/openflow-10.h" + +namespace fluid_msg { + +namespace of10 { + +OutputAction::OutputAction() + : Action(of10::OFPAT_OUTPUT, sizeof(struct of10::ofp_action_output)) { +} + +OutputAction::OutputAction(uint16_t port, uint16_t max_len) + : Action(of10::OFPAT_OUTPUT, sizeof(struct of10::ofp_action_output)) { + this->port_ = port; + this->max_len_ = max_len; +} + +bool OutputAction::equals(const Action &other) { + if (const OutputAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->max_len_ == act->max_len_)); + } + else { + return false; + } +} + +size_t OutputAction::pack(uint8_t *buffer) { + struct of10::ofp_action_output *oa = + (struct of10::ofp_action_output*) buffer; + Action::pack(buffer); + oa->port = hton16(this->port_); + oa->max_len = hton16(this->max_len_); + return 0; +} + +of_error OutputAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_output *oa = + (struct of10::ofp_action_output*) buffer; + Action::unpack(buffer); + this->port_ = ntoh16(oa->port); + this->max_len_ = ntoh16(oa->max_len); + return 0; +} + +SetVLANVIDAction::SetVLANVIDAction() + : Action(of10::OFPAT_SET_VLAN_VID, sizeof(struct of10::ofp_action_vlan_vid)) { +} + +SetVLANVIDAction::SetVLANVIDAction(uint16_t vlan_vid) + : Action(of10::OFPAT_SET_VLAN_VID, sizeof(struct of10::ofp_action_vlan_vid)) { + this->vlan_vid_ = vlan_vid; +} + +bool SetVLANVIDAction::equals(const Action &other) { + if (const SetVLANVIDAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vlan_vid_ == act->vlan_vid_)); + } + else { + return false; + } +} + +size_t SetVLANVIDAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vlan_vid *oa = + (struct of10::ofp_action_vlan_vid*) buffer; + Action::pack(buffer); + oa->vlan_vid = hton16(this->vlan_vid_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetVLANVIDAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vlan_vid *oa = + (struct of10::ofp_action_vlan_vid*) buffer; + Action::unpack(buffer); + this->vlan_vid_ = ntoh16(oa->vlan_vid); + return 0; +} + +SetVLANPCPAction::SetVLANPCPAction() + : Action(of10::OFPAT_SET_VLAN_PCP, sizeof(struct of10::ofp_action_vlan_pcp)) { +} + +SetVLANPCPAction::SetVLANPCPAction(uint8_t vlan_pcp) + : Action(of10::OFPAT_SET_VLAN_PCP, sizeof(struct of10::ofp_action_vlan_pcp)) { + this->vlan_pcp_ = vlan_pcp; +} + +bool SetVLANPCPAction::equals(const Action &other) { + if (const SetVLANPCPAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vlan_pcp_ == act->vlan_pcp_)); + } + else { + return false; + } +} + +size_t SetVLANPCPAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vlan_pcp *oa = + (struct of10::ofp_action_vlan_pcp*) buffer; + Action::pack(buffer); + oa->vlan_pcp = this->vlan_pcp_; + memset(oa->pad, 0x0, 3); + return 0; +} + +of_error SetVLANPCPAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vlan_pcp *oa = + (struct of10::ofp_action_vlan_pcp*) buffer; + Action::unpack(buffer); + this->vlan_pcp_ = oa->vlan_pcp; + return 0; +} + +StripVLANAction::StripVLANAction() + : Action(of10::OFPAT_STRIP_VLAN, sizeof(struct of10::ofp_action_header)) { +} + +size_t StripVLANAction::pack(uint8_t *buffer) { + return Action::pack(buffer); +} + +of_error StripVLANAction::unpack(uint8_t *buffer) { + return Action::unpack(buffer); +} + +SetDLSrcAction::SetDLSrcAction() + : Action(of10::OFPAT_SET_DL_SRC, sizeof(struct of10::ofp_action_dl_addr)) { +} + +SetDLSrcAction::SetDLSrcAction(EthAddress dl_addr) + : Action(of10::OFPAT_SET_DL_SRC, sizeof(struct of10::ofp_action_dl_addr)), + dl_addr_(dl_addr) { +} + +bool SetDLSrcAction::equals(const Action &other) { + if (const SetDLSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->dl_addr_ == act->dl_addr_)); + } + else { + return false; + } +} + +size_t SetDLSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::pack(buffer); + memcpy(oa->dl_addr, this->dl_addr_.get_data(), OFP_ETH_ALEN); + memset(oa->pad, 0x0, OFP_ETH_ALEN); + return 0; +} + +of_error SetDLSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::unpack(buffer); + this->dl_addr_ = EthAddress(oa->dl_addr); + return 0; +} + +SetDLDstAction::SetDLDstAction() + : Action(of10::OFPAT_SET_DL_DST, sizeof(struct of10::ofp_action_dl_addr)) { +} + +SetDLDstAction::SetDLDstAction(EthAddress dl_addr) + : Action(of10::OFPAT_SET_DL_DST, sizeof(struct of10::ofp_action_dl_addr)), + dl_addr_(dl_addr) { +} + +bool SetDLDstAction::equals(const Action &other) { + + if (const SetDLDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->dl_addr_ == act->dl_addr_)); + } + else { + return false; + } +} + +size_t SetDLDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::pack(buffer); + memcpy(oa->dl_addr, this->dl_addr_.get_data(), OFP_ETH_ALEN); + memset(oa->pad, 0x0, OFP_ETH_ALEN); + return 0; +} + +of_error SetDLDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::unpack(buffer); + this->dl_addr_ = EthAddress(oa->dl_addr); + return 0; +} + +SetNWSrcAction::SetNWSrcAction() + : Action(of10::OFPAT_SET_NW_SRC, sizeof(struct of10::ofp_action_nw_addr)) { +} + +SetNWSrcAction::SetNWSrcAction(IPAddress nw_addr) + : Action(of10::OFPAT_SET_NW_SRC, sizeof(struct of10::ofp_action_nw_addr)), + nw_addr_(nw_addr) { +} + +bool SetNWSrcAction::equals(const Action &other) { + if (const SetNWSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_addr_ == act->nw_addr_)); + } + else { + return false; + } +} + +size_t SetNWSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::pack(buffer); + act->nw_addr = hton32(this->nw_addr_.getIPv4()); + return 0; +} + +of_error SetNWSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::unpack(buffer); + this->nw_addr_.setIPv4(ntoh32(act->nw_addr)); + return 0; +} + +SetNWDstAction::SetNWDstAction() + : Action(of10::OFPAT_SET_NW_DST, sizeof(struct of10::ofp_action_nw_addr)) { +} + +SetNWDstAction::SetNWDstAction(IPAddress nw_addr) + : Action(of10::OFPAT_SET_NW_DST, sizeof(struct of10::ofp_action_nw_addr)), + nw_addr_(nw_addr) { +} + +bool SetNWDstAction::equals(const Action &other) { + if (const SetNWDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_addr_ == act->nw_addr_)); + } + else { + return false; + } +} + +size_t SetNWDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::pack(buffer); + act->nw_addr = hton32(this->nw_addr_.getIPv4()); + return 0; +} + +of_error SetNWDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::unpack(buffer); + this->nw_addr_.setIPv4(ntoh32(act->nw_addr)); + return 0; +} + +SetNWTOSAction::SetNWTOSAction() + : Action(of10::OFPAT_SET_NW_TOS, sizeof(struct of10::ofp_action_nw_tos)) { +} + +SetNWTOSAction::SetNWTOSAction(uint8_t nw_tos) + : Action(of10::OFPAT_SET_NW_TOS, sizeof(struct of10::ofp_action_nw_tos)) { + this->nw_tos_ = nw_tos; +} + +bool SetNWTOSAction::equals(const Action &other) { + if (const SetNWTOSAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_tos_ == act->nw_tos_)); + } + else { + return false; + } +} + +size_t SetNWTOSAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_tos *oa = + (struct of10::ofp_action_nw_tos*) buffer; + Action::pack(buffer); + oa->nw_tos = this->nw_tos_; + memset(oa->pad, 0x0, 3); + return 0; +} + +of_error SetNWTOSAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_tos *oa = + (struct of10::ofp_action_nw_tos*) buffer; + Action::unpack(buffer); + this->nw_tos_ = oa->nw_tos; + return 0; +} + +SetTPSrcAction::SetTPSrcAction() + : Action(of10::OFPAT_SET_TP_SRC, sizeof(struct of10::ofp_action_tp_port)) { +} + +SetTPSrcAction::SetTPSrcAction(uint16_t tp_port) + : Action(of10::OFPAT_SET_TP_SRC, sizeof(struct of10::ofp_action_tp_port)) { + this->tp_port_ = tp_port; +} + +bool SetTPSrcAction::equals(const Action &other) { + if (const SetTPSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->tp_port_ == act->tp_port_)); + } + else { + return false; + } +} + +size_t SetTPSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::pack(buffer); + oa->tp_port = hton16(this->tp_port_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetTPSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::unpack(buffer); + this->tp_port_ = ntoh16(oa->tp_port); + return 0; +} + +SetTPDstAction::SetTPDstAction() + : Action(of10::OFPAT_SET_TP_DST, sizeof(struct of10::ofp_action_tp_port)) { +} + +SetTPDstAction::SetTPDstAction(uint16_t tp_port) + : Action(of10::OFPAT_SET_TP_DST, sizeof(struct of10::ofp_action_tp_port)) { + this->tp_port_ = tp_port; +} + +bool SetTPDstAction::equals(const Action &other) { + if (const SetTPDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->tp_port_ == act->tp_port_)); + } + else { + return false; + } +} + +size_t SetTPDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::pack(buffer); + oa->tp_port = hton16(this->tp_port_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetTPDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::unpack(buffer); + this->tp_port_ = ntoh16(oa->tp_port); + return 0; +} + +EnqueueAction::EnqueueAction() + : Action(of10::OFPAT_ENQUEUE, sizeof(struct of10::ofp_action_enqueue)) { +} + +EnqueueAction::EnqueueAction(uint16_t port, uint32_t queue_id) + : Action(of10::OFPAT_ENQUEUE, sizeof(struct of10::ofp_action_enqueue)) { + this->port_ = port; + this->queue_id_ = queue_id; +} + +bool EnqueueAction::equals(const Action &other) { + if (const EnqueueAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->queue_id_ == act->queue_id_)); + } + else { + return false; + } +} + +size_t EnqueueAction::pack(uint8_t *buffer) { + struct of10::ofp_action_enqueue *oa = + (struct of10::ofp_action_enqueue*) buffer; + Action::pack(buffer); + oa->port = hton16(this->port_); + memset(oa->pad, 0x0, 6); + oa->queue_id = hton32(this->queue_id_); + return 0; +} + +of_error EnqueueAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_enqueue *oa = + (struct of10::ofp_action_enqueue*) buffer; + Action::unpack(buffer); + this->port_ = ntoh16(oa->port); + this->queue_id_ = ntoh32(oa->queue_id); + return 0; +} + +VendorAction::VendorAction() + : Action(of10::OFPAT_VENDOR, sizeof(struct of10::ofp_action_vendor_header)) { +} + +VendorAction::VendorAction(uint32_t vendor) + : Action(of10::OFPAT_VENDOR, sizeof(struct of10::ofp_action_vendor_header)) { + this->vendor_ = vendor; +} + +bool VendorAction::equals(const Action &other) { + if (const VendorAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vendor_ == act->vendor_)); + } + else { + return false; + } +} + +size_t VendorAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vendor_header *oa = + (struct of10::ofp_action_vendor_header*) buffer; + Action::pack(buffer); + oa->vendor = hton32(this->vendor_); + return 0; +} + +of_error VendorAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vendor_header *oa = + (struct of10::ofp_action_vendor_header*) buffer; + Action::unpack(buffer); + this->vendor_ = ntoh32(oa->vendor); + return 0; +} + +} // End of namespace of10 + +Action * Action::make_of10_action(uint16_t type) { + switch (type) { + case (of10::OFPAT_OUTPUT): { + return new of10::OutputAction(); + } + case (of10::OFPAT_SET_VLAN_VID): { + return new of10::SetVLANVIDAction(); + } + case (of10::OFPAT_SET_VLAN_PCP): { + return new of10::SetVLANPCPAction(); + } + case (of10::OFPAT_STRIP_VLAN): { + return new of10::StripVLANAction(); + } + case (of10::OFPAT_SET_DL_SRC): { + return new of10::SetDLSrcAction(); + } + case (of10::OFPAT_SET_DL_DST): { + return new of10::SetDLDstAction(); + } + case (of10::OFPAT_SET_NW_SRC): { + return new of10::SetNWSrcAction(); + } + case (of10::OFPAT_SET_NW_DST): { + return new of10::SetNWDstAction(); + } + case (of10::OFPAT_SET_NW_TOS): { + return new of10::SetNWTOSAction(); + } + case (of10::OFPAT_SET_TP_SRC): { + return new of10::SetTPSrcAction(); + } + case (of10::OFPAT_SET_TP_DST): { + return new of10::SetTPDstAction(); + } + case (of10::OFPAT_ENQUEUE): { + return new of10::EnqueueAction(); + } + case (of10::OFPAT_VENDOR): { + return new of10::VendorAction(); + } + } + return NULL; +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10/of10common.cc b/src/ovs/libfluid-msg/of10/of10common.cc new file mode 100644 index 00000000..7a14422a --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10common.cc @@ -0,0 +1,333 @@ +#include "libfluid-msg/of10/of10common.hh" + +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +namespace of10 { + +Port::Port(uint16_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer) + : PortCommon(hw_addr, name, config, state, curr, advertised, supported, + peer) { + this->port_no_ = port_no; +} + +bool Port::operator==(const Port &other) const { + return (PortCommon::operator==(other) && (this->port_no_ == other.port_no_)); +} + +bool Port::operator!=(const Port &other) const { + return !(*this == other); +} + +size_t Port::pack(uint8_t* buffer) { + struct of10::ofp_phy_port *port = (struct of10::ofp_phy_port*) buffer; + port->port_no = hton16(this->port_no_); + memcpy(port->hw_addr, this->hw_addr_.get_data(), OFP_ETH_ALEN); + memset(port->name, 0x0, OFP_MAX_PORT_NAME_LEN); + memcpy(port->name, this->name_.c_str(), + this->name_.size() < OFP_MAX_PORT_NAME_LEN ? + this->name_.size() : OFP_MAX_PORT_NAME_LEN); + port->config = hton32(this->config_); + port->state = hton32(this->state_); + port->curr = hton32(this->curr_); + port->advertised = hton32(this->advertised_); + port->supported = hton32(this->supported_); + port->peer = hton32(this->peer_); + return 0; +} +of_error Port::unpack(uint8_t* buffer) { + struct of10::ofp_phy_port *port = (struct of10::ofp_phy_port*) buffer; + this->port_no_ = ntoh16(port->port_no); + this->hw_addr_ = EthAddress(port->hw_addr); + this->name_ = std::string(port->name); + this->config_ = ntoh32(port->config); + this->state_ = ntoh32(port->state); + this->curr_ = ntoh32(port->curr); + this->advertised_ = ntoh32(port->advertised); + this->supported_ = ntoh32(port->supported); + this->peer_ = ntoh32(port->peer); + return 0; +} + +QueuePropMinRate::QueuePropMinRate(uint16_t rate) + : QueuePropRate(of10::OFPQT_MIN_RATE, rate) { + this->len_ = sizeof(struct of10::ofp_queue_prop_min_rate); +} + +bool QueuePropMinRate::equals(const QueueProperty &other) { + if (const QueuePropMinRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMinRate::pack(uint8_t* buffer) { + struct of10::ofp_queue_prop_min_rate *qp = + (struct of10::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMinRate::unpack(uint8_t* buffer) { + struct of10::ofp_queue_prop_min_rate *qp = + (struct of10::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +PacketQueue::PacketQueue(uint32_t queue_id) + : PacketQueueCommon(queue_id) { + this->len_ = sizeof(struct of10::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, QueuePropertyList properties) + : PacketQueueCommon(queue_id) { + this->properties_ = properties; + this->len_ = sizeof(struct of10::ofp_packet_queue) + properties.length(); +} + +size_t PacketQueue::pack(uint8_t* buffer) { + struct of10::ofp_packet_queue *pq = (struct of10::ofp_packet_queue*) buffer; + pq->queue_id = hton32(this->queue_id_); + pq->len = hton16(this->len_); + memset(pq->pad, 0x0, 2); + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_queue); + this->properties_.pack(p); + return this->len_; +} + +of_error PacketQueue::unpack(uint8_t* buffer) { + struct of10::ofp_packet_queue *pq = (struct of10::ofp_packet_queue*) buffer; + this->queue_id_ = ntoh32(pq->queue_id); + this->len_ = ntoh16(pq->len); + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_queue); + this->properties_.length( + this->len_ - sizeof(struct of10::ofp_packet_queue)); + this->properties_.unpack10(p); + return 0; +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + + this->length_ = sizeof(struct of10::ofp_flow_stats); +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count, of10::Match match, ActionList actions) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + this->match_ = match; + this->actions_ = actions; + this->length_ = sizeof(struct of10::ofp_flow_stats) + actions.length(); +} + +bool FlowStats::operator==(const FlowStats &other) const { + return ((FlowStatsCommon::operator==(other)) + && (this->actions_ == other.actions_) && (this->match_ == other.match_)); +} + +bool FlowStats::operator!=(const FlowStats &other) const { + return !(*this == other); +} + +size_t FlowStats::pack(uint8_t* buffer) { + struct of10::ofp_flow_stats *fs = (struct of10::ofp_flow_stats*) buffer; + this->match_.pack(buffer + 4); + fs->length = hton16(this->length_); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->duration_sec = hton32(this->duration_sec_); + fs->duration_nsec = hton32(this->duration_nsec_); + fs->priority = hton16(this->priority_); + fs->idle_timeout = hton16(this->idle_timeout_); + fs->hard_timeout = hton16(this->hard_timeout_); + memset(fs->pad2, 0x0, 6); + fs->cookie = hton64(this->cookie_); + fs->packet_count = hton64(this->packet_count_); + fs->byte_count = hton64(this->byte_count_); + uint8_t *p = buffer + sizeof(struct of10::ofp_flow_stats); + this->actions_.pack(p); + return this->length_; +} + +of_error FlowStats::unpack(uint8_t* buffer) { + struct of10::ofp_flow_stats *fs = (struct of10::ofp_flow_stats*) buffer; + this->match_.unpack(buffer + 4); + this->length_ = ntoh16(fs->length); + this->table_id_ = fs->table_id; + this->duration_sec_ = ntoh32(fs->duration_sec); + this->duration_nsec_ = ntoh32(fs->duration_nsec); + this->priority_ = ntoh16(fs->priority); + this->idle_timeout_ = ntoh16(fs->idle_timeout); + this->hard_timeout_ = ntoh16(fs->hard_timeout); + this->cookie_ = ntoh64(fs->cookie); + this->packet_count_ = ntoh64(fs->packet_count); + this->byte_count_ = ntoh64(fs->byte_count); + this->actions_.length(this->length_ - sizeof(struct of10::ofp_flow_stats)); + uint8_t * p = buffer + sizeof(struct of10::ofp_flow_stats); + this->actions_.unpack10(p); + return 0; +} + +void FlowStats::actions(ActionList actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void FlowStats::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void FlowStats::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +TableStats::TableStats(uint8_t table_id, std::string name, uint32_t wildcards, + uint32_t max_entries, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count) + : TableStatsCommon(table_id, active_count, lookup_count, matched_count) { + this->name_ = name; + this->wildcards_ = wildcards; + this->max_entries_ = max_entries; +} + +bool TableStats::operator==(const TableStats &other) const { + return ((TableStatsCommon::operator==(other)) + && (this->name_ == other.name_) + && (this->wildcards_ == other.wildcards_) + && (this->max_entries_ == other.max_entries_)); +} + +bool TableStats::operator!=(const TableStats &other) const { + return !(*this == other); +} + +size_t TableStats::pack(uint8_t* buffer) { + struct of10::ofp_table_stats *ts = (struct of10::ofp_table_stats*) buffer; + ts->table_id = this->table_id_; + memset(ts->pad, 0x0, 3); + memset(ts->name, 0x0, OFP_FLUID_MAX_TABLE_NAME_LEN); + memcpy(ts->name, this->name_.c_str(), + this->name_.size() < OFP_FLUID_MAX_TABLE_NAME_LEN ? + this->name_.size() : OFP_FLUID_MAX_TABLE_NAME_LEN); + ts->wildcards = hton32(this->wildcards_); + ts->max_entries = hton32(this->max_entries_); + ts->active_count = hton32(this->active_count_); + ts->lookup_count = hton64(this->lookup_count_); + ts->matched_count = hton64(this->matched_count_); + return 0; +} + +of_error TableStats::unpack(uint8_t* buffer) { + struct of10::ofp_table_stats *ts = (struct of10::ofp_table_stats*) buffer; + this->table_id_ = ts->table_id; + this->name_ = std::string(ts->name); + this->wildcards_ = ntoh32(ts->wildcards); + this->max_entries_ = ntoh32(ts->max_entries); + this->active_count_ = ntoh32(ts->active_count); + this->lookup_count_ = ntoh64(ts->lookup_count); + this->matched_count_ = ntoh64(ts->matched_count); + return 0; +} + +PortStats::PortStats(uint16_t port_no, struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions) + : PortStatsCommon(rx_tx_stats, err_stats, collisions) { + this->port_no_ = port_no; +} + +bool PortStats::operator==(const PortStats &other) const { + return ((PortStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortStats::operator!=(const PortStats &other) const { + return !(*this == other); +} + +size_t PortStats::pack(uint8_t* buffer) { + struct of10::ofp_port_stats *ps = (struct of10::ofp_port_stats*) buffer; + ps->port_no = hton16(this->port_no_); + memset(ps->pad, 0x0, 6); + PortStatsCommon::pack(buffer + 8); + ps->collisions = hton64(this->collisions_); + return 0; +} + +of_error PortStats::unpack(uint8_t* buffer) { + struct of10::ofp_port_stats *ps = (struct of10::ofp_port_stats*) buffer; + this->port_no_ = ntoh16(ps->port_no); + PortStatsCommon::unpack(buffer + 8); + this->collisions_ = ntoh64(ps->collisions); + return 0; +} + +QueueStats::QueueStats(uint16_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors) + : QueueStatsCommon(queue_id, tx_bytes, tx_packets, tx_errors) { + this->port_no_ = port_no; +} + +bool QueueStats::operator==(const QueueStats &other) const { + return ((QueueStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool QueueStats::operator!=(const QueueStats &other) const { + return !(*this == other); +} + +size_t QueueStats::pack(uint8_t* buffer) { + struct of10::ofp_queue_stats *qs = (struct of10::ofp_queue_stats*) buffer; + qs->port_no = hton16(this->port_no_); + memset(qs->pad, 0x0, 2); + qs->queue_id = hton32(this->queue_id_); + qs->tx_bytes = hton64(this->tx_bytes_); + qs->tx_packets = hton64(this->tx_packets_); + qs->tx_errors = hton64(this->tx_errors_); + return 0; +} + +of_error QueueStats::unpack(uint8_t* buffer) { + struct of10::ofp_queue_stats *qs = (struct of10::ofp_queue_stats*) buffer; + this->port_no_ = ntoh16(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + this->tx_bytes_ = ntoh64(qs->tx_bytes); + this->tx_packets_ = ntoh64(qs->tx_packets); + this->tx_errors_ = ntoh64(qs->tx_errors); + return 0; +} + +} //End namespace of13 + +QueueProperty* QueueProperty::make_queue_of10_property(uint16_t property) { + switch (property) { + case (of10::OFPQT_NONE): { + return new QueuePropRate(); + } + case (of10::OFPQT_MIN_RATE): { + return new of10::QueuePropMinRate(); + } + } + return NULL; +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10/of10match.cc b/src/ovs/libfluid-msg/of10/of10match.cc new file mode 100644 index 00000000..72bc63f3 --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10match.cc @@ -0,0 +1,157 @@ +#include "libfluid-msg/of10/of10match.hh" + +namespace fluid_msg { + +namespace of10 { + +Match::Match() + : in_port_(0), + dl_vlan_(0), + dl_vlan_pcp_(0), + dl_type_(0), + nw_tos_(0), + nw_proto_(0), + tp_src_(0), + tp_dst_(0), + dl_src_(), + dl_dst_(), + nw_src_((uint32_t) 0), + nw_dst_((uint32_t) 0), + wildcards_(of10::OFPFW_ALL) { +} + +bool Match::operator==(const Match &other) const { + return ((this->in_port_ == other.in_port_) + && (this->wildcards_ == other.wildcards_) + && (this->dl_vlan_ == other.dl_vlan_) + && (this->dl_vlan_pcp_ == other.dl_vlan_pcp_) + && (this->dl_type_ == other.dl_type_) + && (this->nw_tos_ == other.nw_tos_) + && (this->nw_proto_ == other.nw_proto_) + && (this->tp_src_ == other.tp_src_) && (this->tp_dst_ == other.tp_dst_) + && (this->nw_src_ == other.nw_src_) && (this->nw_dst_ == other.nw_dst_) + && (this->dl_src_ == other.dl_src_) && (this->dl_dst_ == other.dl_dst_)); +} + +bool Match::operator!=(const Match &other) const { + return !(*this == other); +} + +void Match::wildcards(uint32_t wildcards) { + this->wildcards_ = wildcards; +} + +void Match::in_port(uint16_t in_port) { + this->in_port_ = in_port; + this->wildcards_ &= ~of10::OFPFW_IN_PORT; +} + +void Match::dl_src(const EthAddress &dl_src) { + this->dl_src_ = dl_src; + this->wildcards_ &= ~of10::OFPFW_DL_SRC; +} + +void Match::dl_dst(const EthAddress &dl_dst) { + this->dl_dst_ = dl_dst; + this->wildcards_ &= ~of10::OFPFW_DL_DST; +} + +void Match::dl_vlan(uint16_t dl_vlan) { + this->dl_vlan_ = dl_vlan; + this->wildcards_ &= ~of10::OFPFW_DL_VLAN; +} + +void Match::dl_vlan_pcp(uint8_t dl_vlan_pcp) { + this->dl_vlan_pcp_ = dl_vlan_pcp; + this->wildcards_ &= ~of10::OFPFW_DL_VLAN_PCP; +} + +void Match::dl_type(uint16_t dl_type) { + this->dl_type_ = dl_type; + this->wildcards_ &= ~of10::OFPFW_DL_TYPE; +} + +void Match::nw_tos(uint8_t nw_tos) { + this->nw_tos_ = nw_tos; + this->wildcards_ &= ~of10::OFPFW_NW_TOS; +} + +void Match::nw_proto(uint8_t nw_proto) { + this->nw_proto_ = nw_proto; + this->wildcards_ &= ~of10::OFPFW_NW_PROTO; +} + +void Match::nw_src(const IPAddress &nw_src) { + this->nw_src_ = nw_src; + this->wildcards_ &= ~of10::OFPFW_NW_SRC_MASK; +} + +void Match::nw_dst(const IPAddress &nw_dst) { + this->nw_dst_ = nw_dst; + this->wildcards_ &= ~of10::OFPFW_NW_DST_MASK; +} + +void Match::nw_src(const IPAddress &nw_src, uint32_t prefix) { + this->nw_src_ = nw_src; + uint32_t index = 32 - prefix; + this->wildcards_ &= ~of10::OFPFW_NW_SRC_MASK; + this->wildcards_ |= (index << of10::OFPFW_NW_SRC_SHIFT); +} + +void Match::nw_dst(const IPAddress &nw_dst, uint32_t prefix) { + this->nw_dst_ = nw_dst; + uint32_t index = 32 - prefix; + this->wildcards_ &= ~of10::OFPFW_NW_DST_MASK; + this->wildcards_ |= (index << of10::OFPFW_NW_DST_SHIFT); +} + +void Match::tp_src(uint16_t tp_src) { + this->tp_src_ = tp_src; + this->wildcards_ &= ~of10::OFPFW_TP_SRC; +} + +void Match::tp_dst(uint16_t tp_dst) { + this->tp_dst_ = tp_dst; + this->wildcards_ &= ~of10::OFPFW_TP_DST; +} + +size_t Match::pack(uint8_t *buffer) { + struct of10::ofp_match *m = (struct ofp_match*) buffer; + m->wildcards = hton32(this->wildcards_); + m->in_port = hton16(this->in_port_); + memcpy(m->dl_src, this->dl_src_.get_data(), OFP_ETH_ALEN); + memcpy(m->dl_dst, this->dl_dst_.get_data(), OFP_ETH_ALEN); + m->dl_vlan = hton16(this->dl_vlan_); + m->dl_vlan_pcp = this->dl_vlan_pcp_; + memset(m->pad1, 0x0, 1); + m->dl_type = hton16(this->dl_type_); + m->nw_tos = this->nw_tos_; + m->nw_proto = this->nw_proto_; + memset(m->pad2, 0x0, 2); + m->nw_src = hton32(this->nw_src_.getIPv4()); + m->nw_dst = hton32(this->nw_dst_.getIPv4()); + m->tp_src = hton16(this->tp_src_); + m->tp_dst = hton16(this->tp_dst_); + return 0; +} + +of_error Match::unpack(uint8_t *buffer) { + struct of10::ofp_match *m = (struct ofp_match*) buffer; + this->wildcards_ = ntoh32(m->wildcards); + this->in_port_ = ntoh16(m->in_port); + this->dl_src_.set_data(m->dl_src); + this->dl_dst_.set_data(m->dl_dst); + this->dl_vlan_ = ntoh16(m->dl_vlan); + this->dl_vlan_pcp_ = m->dl_vlan_pcp; + this->dl_type_ = ntoh16(m->dl_type); + this->nw_tos_ = m->nw_tos; + this->nw_proto_ = m->nw_proto; + this->nw_src_.setIPv4(ntoh32(m->nw_src)); + this->nw_dst_.setIPv4(ntoh32(m->nw_dst)); + this->tp_src_ = ntoh16(m->tp_src); + this->tp_dst_ = ntoh16(m->tp_dst); + return 0; +} + +} //End of namespace of10 +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10msg.cc b/src/ovs/libfluid-msg/of10msg.cc new file mode 100644 index 00000000..c6f37378 --- /dev/null +++ b/src/ovs/libfluid-msg/of10msg.cc @@ -0,0 +1,1506 @@ +#include "libfluid-msg/of10msg.hh" + +namespace fluid_msg { + +namespace of10 { + +Hello::Hello() + : OFMsg(of10::OFP_VERSION, of10::OFPT_HELLO) { +} + +Hello::Hello(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_HELLO, xid) { +} + +uint8_t* Hello::pack() { + return OFMsg::pack(); +} + +of_error Hello::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +Error::Error() + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR) { + this->length_ = sizeof(struct ofp_fluid_error_msg); +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code) + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR, xid, err_type, code) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len) + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR, xid, err_type, code, + data, data_len) { +} + +EchoRequest::EchoRequest(uint32_t xid) + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REQUEST, xid) { +} + +EchoReply::EchoReply(uint32_t xid) + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REPLY, xid) { +} + +Vendor::Vendor() + : OFMsg(of10::OFP_VERSION, of10::OFPT_VENDOR), + vendor_(0) { + this->length_ = sizeof(struct of10::ofp_vendor_header); +} + +Vendor::Vendor(uint32_t xid, uint32_t vendor) + : OFMsg(of10::OFP_VERSION, of10::OFPT_VENDOR, xid), + vendor_(vendor) { + this->length_ = sizeof(struct of10::ofp_vendor_header); +} + +uint8_t* Vendor::pack() { + uint8_t * buffer = OFMsg::pack(); + struct of10::ofp_vendor_header* v = (struct of10::ofp_vendor_header*) buffer; + v->vendor = hton32(this->vendor_); + return buffer; +} + +of_error Vendor::unpack(uint8_t *buffer) { + struct of10::ofp_vendor_header* v = (struct of10::ofp_vendor_header*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_vendor_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->vendor_ = ntoh32(v->vendor); + return 0; +} + +FeaturesRequest::FeaturesRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_FEATURES_REQUEST) { +} + +FeaturesRequest::FeaturesRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_FEATURES_REQUEST, xid) { +} + +uint8_t* FeaturesRequest::pack() { + return OFMsg::pack(); +} + +of_error FeaturesRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +FeaturesReply::FeaturesReply() + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, 0, 0, 0, + 0, 0) { + this->length_ = sizeof(struct of10::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint32_t capabilities, + uint32_t actions) + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities) { + this->actions_ = actions; + this->length_ = sizeof(struct of10::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint32_t capabilities, + uint32_t actions, std::vector ports) + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities) { + this->actions_ = actions; + this->ports_ = ports; + this->length_ = sizeof(struct of10::ofp_switch_features) + ports_length(); +} + +bool FeaturesReply::operator==(const FeaturesReply &other) const { + return ((FeaturesReplyCommon::operator==(other)) + && (this->actions_ == other.actions_) && (this->ports_ == other.ports_)); +} + +bool FeaturesReply::operator!=(const FeaturesReply &other) const { + return !(*this == other); +} + +uint8_t* FeaturesReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_switch_features *fr = + (struct of10::ofp_switch_features*) buffer; + fr->datapath_id = hton64(this->datapath_id_); + fr->n_buffers = hton32(this->n_buffers_); + fr->n_tables = this->n_tables_; + memset(fr->pad, 0x0, 3); + fr->capabilities = hton32(this->capabilities_); + fr->actions = hton32(this->actions_); + uint8_t *p = buffer + sizeof(struct of10::ofp_switch_features); + for (std::vector::iterator it = this->ports_.begin(), end = + this->ports_.end(); it != end; ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_phy_port); + } + return buffer; +} + +of_error FeaturesReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + struct of10::ofp_switch_features *fr = + (struct of10::ofp_switch_features*) buffer; + this->datapath_id_ = ntoh64(fr->datapath_id); + this->n_buffers_ = ntoh32(fr->n_buffers); + this->n_tables_ = fr->n_tables; + this->capabilities_ = ntoh32(fr->capabilities); + this->actions_ = ntoh32(fr->actions); + size_t len = this->length_ - sizeof(struct of10::ofp_switch_features); + uint8_t *p = buffer + sizeof(struct of10::ofp_switch_features); + while (len) { + of10::Port port; + port.unpack(p); + len -= sizeof(struct of10::ofp_phy_port); + this->ports_.push_back(port); + p += sizeof(struct of10::ofp_phy_port); + } + return 0; +} + +void FeaturesReply::ports(std::vector ports) { + this->ports_ = ports; + this->length_ += ports_length(); +} + +size_t FeaturesReply::ports_length() { + return this->ports_.size() * sizeof(struct of10::ofp_phy_port); +} + +void FeaturesReply::add_port(of10::Port port) { + this->ports_.push_back(port); + this->length_ += sizeof(struct of10::ofp_phy_port); +} + +GetConfigRequest::GetConfigRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REQUEST) { +} + +GetConfigRequest::GetConfigRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REQUEST, xid) { +} + +uint8_t* GetConfigRequest::pack() { + return OFMsg::pack(); +} + +of_error GetConfigRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +GetConfigReply::GetConfigReply() + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REPLY, 0, 0, + 0) { +} + +GetConfigReply::GetConfigReply(uint32_t xid, uint16_t flags, + uint16_t miss_send_len) + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REPLY, xid, + flags, miss_send_len) { +} + +SetConfig::SetConfig() + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_SET_CONFIG) { +} +; + +SetConfig::SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_SET_CONFIG, xid, flags, + miss_send_len) { +} + +FlowMod::FlowMod() + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD), + command_(0), + out_port_(0) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, of10::Match match) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port), + match_(match) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, of10::Match match, + ActionList actions) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port), + match_(match), + actions_(actions) { + this->length_ = sizeof(struct of10::ofp_flow_mod) + actions.length(); +} + +bool FlowMod::operator==(const FlowMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) && + (this->out_port_ == other.out_port_) && (this->match_ == other.match_) + && (this->actions_ == other.actions_)); +} + +bool FlowMod::operator!=(const FlowMod &other) const { + return !(*this == other); +} + +uint8_t* FlowMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_flow_mod *fm = (struct of10::ofp_flow_mod*) buffer; + this->match_.pack(buffer + sizeof(struct ofp_fluid_header)); + fm->cookie = hton64(this->cookie_); + fm->command = hton16(this->command_); + fm->idle_timeout = hton16(this->idle_timeout_); + fm->hard_timeout = hton16(this->hard_timeout_); + fm->priority = hton16(this->priority_); + fm->buffer_id = hton32(this->buffer_id_); + fm->out_port = hton16(this->out_port_); + fm->flags = hton16(this->flags_); + this->actions_.pack(buffer + sizeof(struct of10::ofp_flow_mod)); + return buffer; +} + +of_error FlowMod::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + struct of10::ofp_flow_mod *fm = (struct of10::ofp_flow_mod*) buffer; + if (fm->header.length < sizeof(struct of10::ofp_flow_mod)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->match_.unpack(buffer + sizeof(struct ofp_fluid_header)); + this->cookie_ = ntoh64(fm->cookie); + this->command_ = ntoh16(fm->command); + this->idle_timeout_ = ntoh16(fm->idle_timeout); + this->hard_timeout_ = ntoh16(fm->hard_timeout); + this->priority_ = ntoh16(fm->priority); + this->buffer_id_ = ntoh32(fm->buffer_id); + this->out_port_ = ntoh16(fm->out_port); + this->flags_ = ntoh16(fm->flags); + this->actions_.length(this->length_ - sizeof(struct of10::ofp_flow_mod)); + this->actions_.unpack10(buffer + sizeof(struct of10::ofp_flow_mod)); + return 0; +} + +void FlowMod::actions(const ActionList& actions) { + this->actions_ = actions; + this->length_ += this->actions_.length(); +} + +void FlowMod::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void FlowMod::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +PacketOut::PacketOut() + : PacketOutCommon(of10::OFP_VERSION, of10::OFPT_PACKET_OUT), + in_port_(0) { + this->length_ = sizeof(struct of10::ofp_packet_out); +} + +PacketOut::PacketOut(uint32_t xid, uint32_t buffer_id, uint16_t in_port) + : PacketOutCommon(of10::OFP_VERSION, of10::OFPT_PACKET_OUT, xid, buffer_id), + in_port_(in_port) { + this->length_ = sizeof(struct of10::ofp_packet_out); +} + +bool PacketOut::operator==(const PacketOut &other) const { + return ((PacketOutCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketOut::operator!=(const PacketOut &other) const { + return !(*this == other); +} + +uint8_t* PacketOut::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_packet_out *po = (struct of10::ofp_packet_out*) buffer; + po->buffer_id = hton32(this->buffer_id_); + po->in_port = hton16(this->in_port_); + po->actions_len = hton16(this->actions_len_); + this->actions_.pack(buffer + sizeof(struct of10::ofp_packet_out)); + this->data_len_ = this->length_ + - (sizeof(struct of10::ofp_packet_out) + this->actions_len_); + if (this->buffer_id_ == of10::OFP_NO_BUFFER) { + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_out) + + this->actions_len_; + memcpy(p, this->data_, this->data_len_); + } + return buffer; +} + +of_error PacketOut::unpack(uint8_t *buffer) { + struct of10::ofp_packet_out *po = (struct of10::ofp_packet_out*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_packet_out)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->buffer_id_ = ntoh32(po->buffer_id); + this->in_port_ = ntoh16(po->in_port); + this->actions_len_ = ntoh16(po->actions_len); + this->actions_.length(this->actions_len_); + uint8_t * p = buffer + sizeof(struct of10::ofp_packet_out); + this->actions_.unpack10(p); + this->data_len_ = this->length_ + - (sizeof(struct of10::ofp_packet_out) + this->actions_len_); + if (this->buffer_id_ == of10::OFP_NO_BUFFER) { + /*Reuse p to calculate the packet data position */ + p = buffer + sizeof(struct of10::ofp_packet_out) + this->actions_len_; + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, p, this->data_len_); + } + } + return 0; +} + +PacketIn::PacketIn() + : PacketInCommon(of10::OFP_VERSION, of10::OFPT_PACKET_IN), + in_port_(0) { + this->length_ = sizeof(struct of10::ofp_packet_in) - 2; +} + +PacketIn::PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t in_port, + uint16_t total_len, uint8_t reason) + : PacketInCommon(of10::OFP_VERSION, of10::OFPT_PACKET_IN, xid, buffer_id, + total_len, reason), + in_port_(in_port) { + this->length_ = sizeof(struct of10::ofp_packet_in) - 2; +} + +bool PacketIn::operator==(const PacketIn &other) const { + return ((PacketInCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketIn::operator!=(const PacketIn &other) const { + return !(*this == other); +} + +uint8_t* PacketIn::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_packet_in *pi = (struct of10::ofp_packet_in*) buffer; + pi->buffer_id = hton32(this->buffer_id_); + pi->total_len = hton16(this->total_len_); + pi->in_port = hton16(this->in_port_); + pi->reason = this->reason_; + memset(&pi->pad, 0x0, 1); + if (this->data_len_) { + memcpy(pi->data, this->data_, this->data_len_); + } + return buffer; +} + +of_error PacketIn::unpack(uint8_t *buffer) { + struct of10::ofp_packet_in *pi = (struct of10::ofp_packet_in*) buffer; + OFMsg::unpack(buffer); + this->buffer_id_ = ntoh32(pi->buffer_id); + this->total_len_ = ntoh16(pi->total_len); + this->in_port_ = ntoh16(pi->in_port); + this->reason_ = pi->reason; + this->data_len_ = this->length_ - (sizeof(struct of10::ofp_packet_in) - 2); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, pi->data, this->data_len_); + } + return 0; +} + +FlowRemoved::FlowRemoved() + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count) + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count, + of10::Match match) + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count), + match_(match) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +bool FlowRemoved::operator==(const FlowRemoved &other) const { + return ((FlowRemovedCommon::operator==(other)) + && (this->match_ == other.match_)); +} + +bool FlowRemoved::operator!=(const FlowRemoved &other) const { + return !(*this == other); +} + +uint8_t* FlowRemoved::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_flow_removed *fr = (struct of10::ofp_flow_removed*) buffer; + this->match_.pack(buffer + sizeof(struct ofp_fluid_header)); + fr->cookie = hton64(this->cookie_); + fr->priority = hton16(this->priority_); + fr->reason = this->reason_; + memset(&fr->pad, 0x0, 1); + fr->duration_sec = hton32(this->duration_sec_); + fr->duration_nsec = hton32(this->duration_nsec_); + fr->idle_timeout = hton16(this->idle_timeout_); + memset(fr->pad, 0x0, 2); + fr->packet_count = hton64(this->packet_count_); + fr->byte_count = hton64(this->byte_count_); + return buffer; +} + +of_error FlowRemoved::unpack(uint8_t *buffer) { + struct of10::ofp_flow_removed *fr = (struct of10::ofp_flow_removed*) buffer; + OFMsg::unpack(buffer); + this->match_.unpack(buffer + sizeof(struct ofp_fluid_header)); + this->cookie_ = ntoh64(fr->cookie); + this->priority_ = ntoh16(fr->priority); + this->reason_ = fr->reason; + this->duration_sec_ = ntoh32(fr->duration_sec); + this->duration_nsec_ = ntoh32(fr->duration_nsec); + this->idle_timeout_ = ntoh16(fr->idle_timeout); + this->packet_count_ = ntoh64(fr->packet_count); + this->byte_count_ = ntoh64(fr->byte_count); + return 0; +} + +PortStatus::PortStatus() + : PortStatusCommon(of10::OFP_VERSION, of10::OFPT_PORT_STATUS) { + this->length_ = sizeof(struct of10::ofp_port_status); +} + +PortStatus::PortStatus(uint32_t xid, uint8_t reason, of10::Port desc) + : PortStatusCommon(of10::OFP_VERSION, of10::OFPT_PORT_STATUS, xid, reason), + desc_(desc) { + this->length_ = sizeof(struct of10::ofp_port_status); +} + +bool PortStatus::operator==(const PortStatus &other) const { + return ((PortStatusCommon::operator==(other)) + && (this->desc_ == other.desc_)); +} + +bool PortStatus::operator!=(const PortStatus &other) const { + return !(*this == other); +} + +uint8_t* PortStatus::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_port_status *ps = (struct of10::ofp_port_status *) buffer; + ps->reason = this->reason_; + memset(ps->pad, 0x0, 7); + this->desc_.pack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return buffer; +} + +of_error PortStatus::unpack(uint8_t *buffer) { + struct of10::ofp_port_status *ps = (struct of10::ofp_port_status *) buffer; + OFMsg::unpack(buffer); + this->reason_ = ps->reason; + this->desc_.unpack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return 0; +} + +PortMod::PortMod() + : PortModCommon(of10::OFP_VERSION, of10::OFPT_PORT_MOD), + port_no_(0) { + this->length_ = sizeof(struct of10::ofp_port_mod); +} +; + +PortMod::PortMod(uint32_t xid, uint16_t port_no, EthAddress hw_addr, + uint32_t config, uint32_t mask, uint32_t advertise) + : PortModCommon(of10::OFP_VERSION, of10::OFPT_PORT_MOD, xid, hw_addr, + config, mask, advertise), + port_no_(port_no) { + this->length_ = sizeof(struct of10::ofp_port_mod); +} + +bool PortMod::operator==(const PortMod &other) const { + return ((PortModCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortMod::operator!=(const PortMod &other) const { + return !(*this == other); +} + +uint8_t* PortMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_port_mod *pm = (struct of10::ofp_port_mod *) buffer; + pm->port_no = hton16(this->port_no_); + memcpy(pm->hw_addr, hw_addr_.get_data(), OFP_ETH_ALEN); + pm->config = hton32(this->config_); + pm->mask = hton32(this->mask_); + pm->advertise = hton32(this->advertise_); + memset(pm->pad, 0x0, 4); + return buffer; +} + +of_error PortMod::unpack(uint8_t* buffer) { + struct of10::ofp_port_mod *pm = (struct of10::ofp_port_mod *) buffer; + if (pm->header.length < sizeof(struct of10::ofp_port_mod)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + OFMsg::unpack(buffer); + this->port_no_ = ntoh16(pm->port_no); + this->hw_addr_ = EthAddress(pm->hw_addr); + this->config_ = ntoh32(pm->config); + this->mask_ = ntoh32(pm->mask); + this->advertise_ = ntoh32(pm->advertise); + return 0; +} + +StatsRequest::StatsRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST), + stats_type_(0), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +StatsRequest::StatsRequest(uint16_t type) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST), + stats_type_(type), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +StatsRequest::StatsRequest(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST, xid), + stats_type_(type), + flags_(flags) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +bool StatsRequest::operator==(const StatsRequest &other) const { + return ((OFMsg::operator==(other)) + && (this->stats_type_ == other.stats_type_) + && (this->flags_ == other.flags_)); +} + +bool StatsRequest::operator!=(const StatsRequest &other) const { + return !(*this == other); +} + +uint8_t* StatsRequest::pack() { + uint8_t *buffer = OFMsg::pack(); + struct of10::ofp_stats_request * sr = + (struct of10::ofp_stats_request *) buffer; + + sr->type = hton16(this->stats_type_); + sr->flags = hton16(this->flags_); + return buffer; +} + +of_error StatsRequest::unpack(uint8_t *buffer) { + struct of10::ofp_stats_request * sr = + (struct of10::ofp_stats_request *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_stats_request)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->stats_type_ = ntoh16(sr->type); + this->flags_ = ntoh16(sr->flags); + return 0; +} + +StatsReply::StatsReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY), + stats_type_(0), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +StatsReply::StatsReply(uint16_t type) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY), + stats_type_(type), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +StatsReply::StatsReply(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY, xid) { + this->stats_type_ = type; + this->flags_ = flags; + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +bool StatsReply::operator==(const StatsReply &other) const { + return ((OFMsg::operator==(other)) + && (this->stats_type_ == other.stats_type_) + && (this->flags_ == other.flags_)); +} + +bool StatsReply::operator!=(const StatsReply &other) const { + return !(*this == other); +} + +uint8_t* StatsReply::pack() { + uint8_t *buffer = OFMsg::pack(); + struct of10::ofp_stats_reply * sr = (struct of10::ofp_stats_reply *) buffer; + sr->type = hton16(this->stats_type_); + sr->flags = hton16(this->flags_); + return buffer; +} + +of_error StatsReply::unpack(uint8_t *buffer) { + struct of10::ofp_stats_reply * sr = (struct of10::ofp_stats_reply *) buffer; + OFMsg::unpack(buffer); + this->stats_type_ = ntoh16(sr->type); + this->flags_ = ntoh16(sr->flags); + return 0; +} + +StatsRequestDesc::StatsRequestDesc() + : StatsRequest(OFPST_DESC) { +} + +StatsRequestDesc::StatsRequestDesc(uint32_t xid, uint16_t flags) + : StatsRequest(xid, of10::OFPST_DESC, flags) { +} + +uint8_t* StatsRequestDesc::pack() { + uint8_t* buffer = StatsRequest::pack(); + return buffer; +} + +of_error StatsRequestDesc::unpack(uint8_t *buffer) { + return StatsRequest::unpack(buffer); +} + +StatsReplyDesc::StatsReplyDesc() + : StatsReply(OFPST_DESC) { + this->length_ += sizeof(struct ofp_desc); +} + +StatsReplyDesc::StatsReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc) + : StatsReply(xid, of10::OFPST_DESC, flags), + desc_(desc) { + this->length_ += sizeof(struct ofp_desc); +} + +StatsReplyDesc::StatsReplyDesc(uint32_t xid, uint16_t flags, + std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc) + : StatsReply(xid, of10::OFPST_DESC, flags), + desc_(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) { + this->length_ += sizeof(struct ofp_desc); +} + +bool StatsReplyDesc::operator==(const StatsReplyDesc &other) const { + return ((StatsReply::operator==(other)) && (this->desc_ == other.desc_)); +} + +bool StatsReplyDesc::operator!=(const StatsReplyDesc &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyDesc::pack() { + uint8_t* buffer = StatsReply::pack(); + this->desc_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + return buffer; +} + +of_error StatsReplyDesc::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + return this->desc_.unpack(buffer + sizeof(struct of10::ofp_stats_reply)); +} + +void StatsReplyDesc::desc(SwitchDesc desc) { + this->desc_ = desc; + this->length_ += sizeof(struct ofp_desc); +} + +StatsRequestFlow::StatsRequestFlow() + : StatsRequest(OFPST_FLOW) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +StatsRequestFlow::StatsRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_FLOW, flags), + table_id_(table_id), + out_port_(out_port) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +StatsRequestFlow::StatsRequestFlow(uint32_t xid, uint16_t flags, + of10::Match match, uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + match_(match) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +bool StatsRequestFlow::operator==(const StatsRequestFlow &other) const { + return ((StatsRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->match_ == other.match_)); +} + +bool StatsRequestFlow::operator!=(const StatsRequestFlow &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestFlow::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_flow_stats_request *fs = + (struct of10::ofp_flow_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + this->match_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->out_port = hton16(this->out_port_); + return buffer; +} + +of_error StatsRequestFlow::unpack(uint8_t *buffer) { + struct of10::ofp_flow_stats_request *fs = + (struct of10::ofp_flow_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_flow_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = hton16(fs->out_port); + return this->match_.unpack(buffer + sizeof(struct of10::ofp_stats_request)); +} + +StatsReplyFlow::StatsReplyFlow() + : StatsReply(OFPST_FLOW) { +} + +StatsReplyFlow::StatsReplyFlow(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_FLOW, flags) { +} +StatsReplyFlow::StatsReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats) + : StatsReply(xid, of10::OFPST_FLOW, flags), + flow_stats_(flow_stats) { + this->length_ += flow_stats.size() * sizeof(struct ofp_flow_stats); +} + +bool StatsReplyFlow::operator==(const StatsReplyFlow &other) const { + return ((StatsReply::operator==(other)) + && (this->flow_stats_ == other.flow_stats_)); +} + +bool StatsReplyFlow::operator!=(const StatsReplyFlow &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyFlow::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_request); + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error StatsReplyFlow::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + FlowStats stat; + stat.unpack(p); + this->flow_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void StatsReplyFlow::flow_stats(std::vector flow_stats) { + this->flow_stats_ = flow_stats; + this->length_ += this->flow_stats_.size() * sizeof(struct ofp_flow_stats); +} + +void StatsReplyFlow::add_flow_stats(of10::FlowStats stats) { + this->flow_stats_.push_back(stats); + this->length_ += stats.length(); +} + +StatsRequestAggregate::StatsRequestAggregate() + : StatsRequest(OFPST_AGGREGATE) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +StatsRequestAggregate::StatsRequestAggregate(uint32_t xid, uint16_t flags, + uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_AGGREGATE, flags) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +StatsRequestAggregate::StatsRequestAggregate(uint32_t xid, uint16_t flags, + of10::Match match, uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + match_(match) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +bool StatsRequestAggregate::operator==( + const StatsRequestAggregate &other) const { + return ((StatsRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->match_ == other.match_)); +} + +bool StatsRequestAggregate::operator!=( + const StatsRequestAggregate &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestAggregate::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_aggregate_stats_request *fs = + (struct of10::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + this->match_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->out_port = hton16(this->out_port_); + return buffer; +} + +of_error StatsRequestAggregate::unpack(uint8_t *buffer) { + struct of10::ofp_aggregate_stats_request *fs = + (struct of10::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + + sizeof(of10::ofp_aggregate_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = hton16(fs->out_port); + return this->match_.unpack(buffer + sizeof(struct of10::ofp_stats_request)); +} + +StatsReplyAggregate::StatsReplyAggregate() + : StatsReply(OFPST_AGGREGATE) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_reply); +} + +StatsReplyAggregate::StatsReplyAggregate(uint32_t xid, uint16_t flags, + uint64_t packet_count, uint64_t byte_count, uint32_t flow_count) + : StatsReply(xid, of10::OFPST_AGGREGATE, flags), + packet_count_(packet_count), + byte_count_(byte_count), + flow_count_(flow_count) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_reply); +} + +bool StatsReplyAggregate::operator==(const StatsReplyAggregate &other) const { + return ((StatsReply::operator==(other)) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->flow_count_ == other.flow_count_)); +} + +bool StatsReplyAggregate::operator!=(const StatsReplyAggregate &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyAggregate::pack() { + uint8_t* buffer = StatsReply::pack(); + struct of10::ofp_aggregate_stats_reply *ar = + (struct of10::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of10::ofp_stats_reply)); + ar->packet_count = hton64(this->packet_count_); + ar->byte_count = hton64(this->byte_count_); + ar->flow_count = hton32(this->flow_count_); + memset(ar->pad, 0x0, 4); + return buffer; +} + +of_error StatsReplyAggregate::unpack(uint8_t *buffer) { + struct of10::ofp_aggregate_stats_reply *ar = + (struct of10::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of10::ofp_stats_reply)); + StatsReply::unpack(buffer); + this->packet_count_ = ntoh64(ar->packet_count); + this->byte_count_ = ntoh64(ar->byte_count); + this->flow_count_ = ntoh32(ar->flow_count); + return 0; +} + +StatsRequestTable::StatsRequestTable() + : StatsRequest(OFPST_TABLE) { +} + +StatsRequestTable::StatsRequestTable(uint32_t xid, uint16_t flags) + : StatsRequest(xid, of10::OFPST_TABLE, flags) { +} + +uint8_t* StatsRequestTable::pack() { + uint8_t* buffer = StatsRequest::pack(); + return buffer; +} + +of_error StatsRequestTable::unpack(uint8_t *buffer) { + return StatsRequest::unpack(buffer); +} + +StatsReplyTable::StatsReplyTable() + : StatsReply(OFPST_TABLE) { +} + +StatsReplyTable::StatsReplyTable(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_TABLE, flags) { +} + +StatsReplyTable::StatsReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats) + : StatsReply(xid, of10::OFPST_TABLE, flags), + table_stats_(table_stats) { + this->length_ += table_stats.size() * sizeof(struct of10::ofp_table_stats); +} + +bool StatsReplyTable::operator==(const StatsReplyTable &other) const { + return ((StatsReply::operator==(other)) + && (this->table_stats_ == other.table_stats_)); +} + +bool StatsReplyTable::operator!=(const StatsReplyTable &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyTable::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = this->table_stats_.begin(); + it != this->table_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_table_stats); + } + return buffer; +} + +of_error StatsReplyTable::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + TableStats stat; + stat.unpack(p); + this->table_stats_.push_back(stat); + p += sizeof(struct of10::ofp_table_stats); + len -= sizeof(struct of10::ofp_table_stats); + } + return 0; +} + +void StatsReplyTable::table_stats(std::vector table_stats) { + this->table_stats_ = table_stats; + this->length_ += table_stats.size() * sizeof(struct of10::ofp_table_stats); +} + +void StatsReplyTable::add_table_stat(of10::TableStats stat) { + this->table_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_table_stats); +} + +StatsRequestPort::StatsRequestPort() + : StatsRequest(OFPST_PORT) { + this->length_ += sizeof(struct of10::ofp_port_stats_request); +} + +StatsRequestPort::StatsRequestPort(uint32_t xid, uint16_t flags, + uint16_t port_no) + : StatsRequest(xid, of10::OFPST_PORT, flags), + port_no_(port_no) { + this->length_ += sizeof(struct of10::ofp_port_stats_request); +} +; + +bool StatsRequestPort::operator==(const StatsRequestPort &other) const { + return ((StatsRequest::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool StatsRequestPort::operator!=(const StatsRequestPort &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestPort::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_port_stats_request *ps = + (struct of10::ofp_port_stats_request *) (buffer + + sizeof(struct of10::ofp_stats_request)); + ps->port_no = hton16(this->port_no_); + memset(ps->pad, 0x0, 6); + return buffer; +} + +of_error StatsRequestPort::unpack(uint8_t *buffer) { + struct of10::ofp_port_stats_request *ps = + (struct of10::ofp_port_stats_request *) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_port_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh16(ps->port_no); + return 0; +} + +StatsReplyPort::StatsReplyPort() + : StatsReply(OFPST_PORT) { +} + +StatsReplyPort::StatsReplyPort(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_PORT, flags) { +} + +StatsReplyPort::StatsReplyPort(uint32_t xid, uint16_t flags, + std::vector port_stats) + : StatsReply(xid, of10::OFPST_PORT, flags), + port_stats_(port_stats) { + this->length_ += port_stats.size() * sizeof(struct of10::ofp_port_stats); +} + +bool StatsReplyPort::operator==(const StatsReplyPort &other) const { + return ((StatsReply::operator==(other)) + && (this->port_stats_ == other.port_stats_)); +} + +bool StatsReplyPort::operator!=(const StatsReplyPort &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyPort::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = this->port_stats_.begin(); + it != this->port_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_port_stats); + } + return buffer; +} + +of_error StatsReplyPort::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_request); + while (len) { + of10::PortStats stat; + stat.unpack(p); + this->port_stats_.push_back(stat); + p += sizeof(struct of10::ofp_port_stats); + len -= sizeof(struct of10::ofp_port_stats); + } + return 0; +} + +void StatsReplyPort::port_stats(std::vector port_stats) { + this->port_stats_ = port_stats; + this->length_ += port_stats.size() * sizeof(struct of10::ofp_port_stats); +} + +void StatsReplyPort::add_port_stat(of10::PortStats stat) { + this->port_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_port_stats); +} + +StatsRequestQueue::StatsRequestQueue() + : StatsRequest(OFPST_QUEUE) { + this->length_ += sizeof(struct of10::ofp_queue_stats_request); +} + +StatsRequestQueue::StatsRequestQueue(uint32_t xid, uint16_t flags, + uint16_t port_no, uint32_t queue_id) + : StatsRequest(xid, of10::OFPST_QUEUE, flags), + port_no_(port_no), + queue_id_(queue_id) { + this->length_ += sizeof(struct of10::ofp_queue_stats_request); +} + +bool StatsRequestQueue::operator==(const StatsRequestQueue &other) const { + return ((StatsRequest::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->queue_id_ == other.queue_id_)); +} + +bool StatsRequestQueue::operator!=(const StatsRequestQueue &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestQueue::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_queue_stats_request* qs = + (of10::ofp_queue_stats_request*) (buffer + + sizeof(of10::ofp_stats_request)); + qs->port_no = hton16(this->port_no_); + memset(qs->pad, 0x0, 2); + qs->queue_id = hton32(this->queue_id_); + return buffer; +} + +of_error StatsRequestQueue::unpack(uint8_t *buffer) { + struct of10::ofp_queue_stats_request* qs = + (of10::ofp_queue_stats_request*) (buffer + + sizeof(of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_queue_stats_request)) { + return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + } + this->port_no_ = hton16(qs->port_no); + this->queue_id_ = hton32(qs->queue_id); + return 0; +} + +StatsReplyQueue::StatsReplyQueue() + : StatsReply(OFPST_QUEUE) { +} + +StatsReplyQueue::StatsReplyQueue(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_QUEUE, flags) { +} + +StatsReplyQueue::StatsReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats) + : StatsReply(xid, of10::OFPST_QUEUE, flags), + queue_stats_(queue_stats) { + this->length_ += sizeof(struct of10::ofp_queue_stats); +} + +bool StatsReplyQueue::operator==(const StatsReplyQueue &other) const { + return ((StatsReply::operator==(other)) + && (this->queue_stats_ == other.queue_stats_)); +} + +bool StatsReplyQueue::operator!=(const StatsReplyQueue &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyQueue::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = + this->queue_stats_.begin(); it != this->queue_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_queue_stats); + } + return buffer; +} + +of_error StatsReplyQueue::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + of10::QueueStats stat; + stat.unpack(p); + this->queue_stats_.push_back(stat); + p += sizeof(struct of10::ofp_queue_stats); + len -= sizeof(struct of10::ofp_queue_stats); + } + return 0; +} + +void StatsReplyQueue::queue_stats(std::vector queue_stats) { + this->queue_stats_ = queue_stats; + this->length_ += queue_stats.size() * sizeof(struct of10::ofp_queue_stats); +} + +void StatsReplyQueue::add_queue_stat(of10::QueueStats stat) { + this->queue_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_queue_stats); +} + +StatsRequestVendor::StatsRequestVendor() + : StatsRequest(OFPST_VENDOR) { + this->length_ += 4; +} + +StatsRequestVendor::StatsRequestVendor(uint32_t xid, uint16_t flags, + uint32_t vendor) + : StatsRequest(xid, of10::OFPST_VENDOR, flags), + vendor_(vendor) { + this->length_ += 4; +} + +bool StatsRequestVendor::operator==(const StatsRequestVendor &other) const { + return ((StatsRequest::operator==(other)) + && (this->vendor_ == other.vendor_)); +} + +bool StatsRequestVendor::operator!=(const StatsRequestVendor &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestVendor::pack() { + uint8_t* buffer = StatsRequest::pack(); + uint32_t vendor = hton32(this->vendor_); + memcpy(buffer + sizeof(struct of10::ofp_stats_request), &vendor, + sizeof(uint32_t)); + return buffer; +} + +of_error StatsRequestVendor::unpack(uint8_t *buffer) { + StatsRequest::unpack(buffer); + uint32_t vendor; + memcpy(&vendor, buffer + sizeof(struct of10::ofp_stats_request), + sizeof(uint32_t)); + this->vendor_ = ntoh32(this->vendor_); + return 0; +} + +StatsReplyVendor::StatsReplyVendor() + : StatsReply(OFPST_VENDOR) { + this->length_ += 4; +} + +StatsReplyVendor::StatsReplyVendor(uint32_t xid, uint16_t flags, + uint32_t vendor) + : StatsReply(xid, of10::OFPST_VENDOR, flags), + vendor_(vendor) { + this->length_ += 4; +} + +bool StatsReplyVendor::operator==(const StatsReplyVendor &other) const { + return ((StatsReply::operator==(other)) && (this->vendor_ == other.vendor_)); +} + +bool StatsReplyVendor::operator!=(const StatsReplyVendor &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyVendor::pack() { + uint8_t* buffer = StatsReply::pack(); + uint32_t vendor = hton32(this->vendor_); + memcpy(buffer + sizeof(struct of10::ofp_stats_reply), &vendor, + sizeof(uint32_t)); + return buffer; +} + +of_error StatsReplyVendor::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint32_t vendor; + memcpy(&vendor, buffer + sizeof(struct of10::ofp_stats_reply), + sizeof(uint32_t)); + this->vendor_ = ntoh32(this->vendor_); + return 0; +} + +QueueGetConfigRequest::QueueGetConfigRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REQUEST) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_request); +} + +QueueGetConfigRequest::QueueGetConfigRequest(uint32_t xid, uint16_t port) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REQUEST, xid), + port_(port) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_request); +} + +bool QueueGetConfigRequest::operator==( + const QueueGetConfigRequest &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_)); +} + +bool QueueGetConfigRequest::operator!=( + const QueueGetConfigRequest &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_queue_get_config_request * qc = + (struct of10::ofp_queue_get_config_request*) buffer; + qc->port = hton16(this->port_); + memset(qc->pad, 0x0, 2); + return buffer; +} + +of_error QueueGetConfigRequest::unpack(uint8_t *buffer) { + struct of10::ofp_queue_get_config_request * qc = + (struct of10::ofp_queue_get_config_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(ofp_queue_get_config_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->port_ = ntoh16(qc->port); + return 0; +} + +QueueGetConfigReply::QueueGetConfigReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port), + queues_(queues) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply) + + queues_len(); +} + +bool QueueGetConfigReply::operator==(const QueueGetConfigReply &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_) + && (this->queues_ == other.queues_)); +} + +bool QueueGetConfigReply::operator!=(const QueueGetConfigReply &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_queue_get_config_reply *qr = + (struct of10::ofp_queue_get_config_reply *) buffer; + qr->port = hton16(this->port_); + memset(qr->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of10::ofp_queue_get_config_reply); + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error QueueGetConfigReply::unpack(uint8_t *buffer) { + struct of10::ofp_queue_get_config_reply *qr = + (struct of10::ofp_queue_get_config_reply *) buffer; + OFMsg::unpack(buffer); + this->port_ = ntoh16(qr->port); + uint8_t *p = buffer + sizeof(struct of10::ofp_queue_get_config_reply); + size_t len = this->length_ + - sizeof(struct of10::ofp_queue_get_config_reply); + while (len) { + PacketQueue pq; + pq.unpack(p); + this->queues_.push_back(pq); + p += pq.len(); + len -= pq.len(); + } + return 0; +} + +void QueueGetConfigReply::queues(std::list queues) { + this->queues_ = queues; + this->length_ += queues_len(); +} + +void QueueGetConfigReply::add_queue(PacketQueue queue) { + this->queues_.push_back(queue); + this->length_ += queue.len(); +} + +size_t QueueGetConfigReply::queues_len() { + size_t len; + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + len += it->len(); + } + return len; +} + +BarrierRequest::BarrierRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REQUEST) { +} + +BarrierRequest::BarrierRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REQUEST, xid) { +} + +uint8_t* BarrierRequest::pack() { + return OFMsg::pack(); +} + +of_error BarrierRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + } + return 0; +} + +BarrierReply::BarrierReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REPLY) { +} + +BarrierReply::BarrierReply(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REPLY, xid) { +} + +uint8_t* BarrierReply::pack() { + return OFMsg::pack(); + +} + +of_error BarrierReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + return 0; +} + +} //End namespace of10. +} //End of namespace fluid_msg. diff --git a/src/ovs/libfluid-msg/of13/of13action.cc b/src/ovs/libfluid-msg/of13/of13action.cc new file mode 100644 index 00000000..0e79af12 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13action.cc @@ -0,0 +1,626 @@ +#include "libfluid-msg/of13/of13action.hh" + +namespace fluid_msg { + +namespace of13 { + +OutputAction::OutputAction() + : set_order_(230), + Action(of13::OFPAT_OUTPUT, sizeof(struct of13::ofp_action_output)) { +} + +bool OutputAction::equals(const Action &other) { + + if (const OutputAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->max_len_ == act->max_len_)); + } + else { + return false; + } +} + +OutputAction::OutputAction(uint32_t port, uint16_t max_len) + : set_order_(230), + Action(of13::OFPAT_OUTPUT, sizeof(struct of13::ofp_action_output)) { + this->port_ = port; + this->max_len_ = max_len; +} + +size_t OutputAction::pack(uint8_t* buffer) { + struct of13::ofp_action_output* ao = + (struct of13::ofp_action_output*) buffer; + Action::pack(buffer); + ao->port = hton32(this->port_); + ao->max_len = hton16(this->max_len_); + memset(ao->pad, 0x0, 6); + return 0; +} + +of_error OutputAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_output* ao = + (struct of13::ofp_action_output*) buffer; + Action::unpack(buffer); + this->port_ = ntoh32(ao->port); + this->max_len_ = ntoh16(ao->max_len); + return 0; +} + +CopyTTLInAction::CopyTTLInAction() + : set_order_(10), + Action(of13::OFPAT_COPY_TTL_IN, sizeof(struct ofp_action_header)) { +} + +size_t CopyTTLInAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error CopyTTLInAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +CopyTTLOutAction::CopyTTLOutAction() + : set_order_(110), + Action(of13::OFPAT_COPY_TTL_OUT, sizeof(struct ofp_action_header)) { +} + +size_t CopyTTLOutAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error CopyTTLOutAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +SetMPLSTTLAction::SetMPLSTTLAction() + : set_order_(140), + Action(of13::OFPAT_SET_MPLS_TTL, sizeof(struct of13::ofp_action_mpls_ttl)) { +} + +SetMPLSTTLAction::SetMPLSTTLAction(uint8_t mpls_ttl) + : set_order_(140), + Action(of13::OFPAT_SET_MPLS_TTL, sizeof(struct of13::ofp_action_mpls_ttl)) { + this->mpls_ttl_ = mpls_ttl; +} + +bool SetMPLSTTLAction::equals(const Action &other) { + + if (const SetMPLSTTLAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->mpls_ttl_ == act->mpls_ttl_)); + } + else { + return false; + } +} + +size_t SetMPLSTTLAction::pack(uint8_t* buffer) { + struct of13::ofp_action_mpls_ttl * mt = + (struct of13::ofp_action_mpls_ttl*) buffer; + Action::pack(buffer); + mt->mpls_ttl = this->mpls_ttl_; + memset(mt->pad, 0x0, 3); + return 0; +} + +of_error SetMPLSTTLAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_mpls_ttl * mt = + (struct of13::ofp_action_mpls_ttl*) buffer; + Action::unpack(buffer); + this->mpls_ttl_ = mt->mpls_ttl; + return 0; +} + +DecMPLSTTLAction::DecMPLSTTLAction() + : set_order_(120), + Action(of13::OFPAT_DEC_MPLS_TTL, sizeof(struct ofp_action_header)) { +} + +size_t DecMPLSTTLAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error DecMPLSTTLAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +PushVLANAction::PushVLANAction() + : set_order_(100), + Action(of13::OFPAT_PUSH_VLAN, sizeof(struct of13::ofp_action_push)) { +} + +PushVLANAction::PushVLANAction(uint16_t ethertype) + : set_order_(100), + Action(of13::OFPAT_PUSH_VLAN, sizeof(struct of13::ofp_action_push)) { + this->ethertype_ = ethertype; +} + +bool PushVLANAction::equals(const Action &other) { + + if (const PushVLANAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushVLANAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushVLANAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopVLANAction::PopVLANAction() + : set_order_(30), + Action(of13::OFPAT_POP_VLAN, sizeof(struct ofp_action_header)) { +} + +size_t PopVLANAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error PopVLANAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +PushMPLSAction::PushMPLSAction() + : set_order_(80), + Action(of13::OFPAT_PUSH_MPLS, sizeof(struct ofp_action_header)) { +} + +PushMPLSAction::PushMPLSAction(uint16_t ethertype) + : set_order_(80), + Action(of13::OFPAT_PUSH_MPLS, sizeof(struct ofp_action_header)) { + this->ethertype_ = ethertype; +} + +bool PushMPLSAction::equals(const Action &other) { + + if (const PushMPLSAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushMPLSAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushMPLSAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopMPLSAction::PopMPLSAction() + : set_order_(40), + Action(of13::OFPAT_POP_MPLS, sizeof(struct of13::ofp_action_pop_mpls)) { +} + +PopMPLSAction::PopMPLSAction(uint16_t ethertype) + : set_order_(40), + Action(of13::OFPAT_POP_MPLS, sizeof(struct of13::ofp_action_pop_mpls)) { + this->ethertype_ = ethertype; +} + +bool PopMPLSAction::equals(const Action &other) { + + if (const PopMPLSAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PopMPLSAction::pack(uint8_t* buffer) { + struct of13::ofp_action_pop_mpls *pm = + (struct of13::ofp_action_pop_mpls*) buffer; + Action::pack(buffer); + pm->ethertype = hton16(this->ethertype_); + memset(pm->pad, 0x0, 2); + return 0; +} + +of_error PopMPLSAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_pop_mpls *pm = + (struct of13::ofp_action_pop_mpls*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(pm->ethertype); + return 0; +} + +SetQueueAction::SetQueueAction() + : set_order_(170), + Action(of13::OFPAT_SET_QUEUE, sizeof(struct of13::ofp_action_set_queue)) { +} + +SetQueueAction::SetQueueAction(uint32_t queue_id) + : set_order_(170), + Action(of13::OFPAT_SET_QUEUE, sizeof(struct of13::ofp_action_set_queue)) { + this->queue_id_ = queue_id; +} + +bool SetQueueAction::equals(const Action &other) { + + if (const SetQueueAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->queue_id_ == act->queue_id_)); + } + else { + return false; + } +} + +size_t SetQueueAction::pack(uint8_t* buffer) { + struct of13::ofp_action_set_queue* aq = + (struct of13::ofp_action_set_queue*) buffer; + Action::pack(buffer); + aq->queue_id = hton32(this->queue_id_); + return 0; +} + +of_error SetQueueAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_set_queue* aq = + (struct of13::ofp_action_set_queue*) buffer; + Action::unpack(buffer); + this->queue_id_ = ntoh32(aq->queue_id); + return 0; +} + +GroupAction::GroupAction() + : set_order_(220), + Action(of13::OFPAT_GROUP, sizeof(struct of13::ofp_action_group)) { +} + +GroupAction::GroupAction(uint32_t group_id) + : set_order_(220), + Action(of13::OFPAT_GROUP, sizeof(struct of13::ofp_action_group)) { + this->group_id_ = group_id; +} + +bool GroupAction::equals(const Action &other) { + + if (const GroupAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->group_id_ == act->group_id_)); + } + else { + return false; + } +} + +size_t GroupAction::pack(uint8_t* buffer) { + struct of13::ofp_action_group *ag = (struct of13::ofp_action_group*) buffer; + Action::pack(buffer); + ag->group_id = hton32(this->group_id_); + return 0; +} + +of_error GroupAction::unpack(uint8_t *buffer) { + struct ofp_action_group *ag = (struct ofp_action_group*) buffer; + Action::unpack(buffer); + this->group_id_ = ntoh32(ag->group_id); + return 0; +} + +SetNWTTLAction::SetNWTTLAction() + : set_order_(150), + Action(of13::OFPAT_SET_NW_TTL, sizeof(struct of13::ofp_action_nw_ttl)) { +} + +SetNWTTLAction::SetNWTTLAction(uint8_t nw_ttl) + : set_order_(150), + Action(of13::OFPAT_SET_NW_TTL, sizeof(struct of13::ofp_action_nw_ttl)) { + this->nw_ttl_ = nw_ttl; +} + +bool SetNWTTLAction::equals(const Action &other) { + + if (const SetNWTTLAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_ttl_ == act->nw_ttl_)); + } + else { + return false; + } +} + +size_t SetNWTTLAction::pack(uint8_t* buffer) { + struct of13::ofp_action_nw_ttl *nt = + (struct of13::ofp_action_nw_ttl*) buffer; + Action::pack(buffer); + nt->nw_ttl = this->nw_ttl_; + memset(nt->pad, 0x0, 3); + return 0; +} + +of_error SetNWTTLAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_nw_ttl *nt = + (struct of13::ofp_action_nw_ttl*) buffer; + Action::unpack(buffer); + this->nw_ttl_ = nt->nw_ttl; + return 0; +} + +DecNWTTLAction::DecNWTTLAction() + : set_order_(130), + Action(of13::OFPAT_DEC_NW_TTL, sizeof(struct ofp_action_header)) { +} + +size_t DecNWTTLAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error DecNWTTLAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +SetFieldAction::SetFieldAction() + : set_order_(160), + Action(of13::OFPAT_SET_FIELD, sizeof(struct of13::ofp_action_set_field)) { + +} + +SetFieldAction::SetFieldAction(OXMTLV* field) + : set_order_(160), + Action(of13::OFPAT_SET_FIELD, sizeof(struct of13::ofp_action_set_field)) { + this->field(field); +} + +SetFieldAction::SetFieldAction(const SetFieldAction &other) + : set_order_(160) { + this->type_ = other.type_; + this->length_ = other.length_; + this->field_ = other.field_->clone(); +} + +void SetFieldAction::field(OXMTLV* field) { + this->field_ = field; + this->length_ += ROUND_UP(field->length(), 8); +} + +SetFieldAction::~SetFieldAction() { + delete this->field_; +} + +void swap(SetFieldAction& first, SetFieldAction& second) { + std::swap(first.type_, second.type_); + std::swap(first.length_, second.length_); + std::swap(*(first.field_), *(second.field_)); +} + +SetFieldAction& SetFieldAction::operator=(SetFieldAction other) { + swap(*this, other); + return *this; +} + +bool SetFieldAction::equals(const Action &other) { + const SetFieldAction * action; + if (const SetFieldAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->field_->equals(*act->field_)) + && (this->length_ == act->length_)); + } + else { + return false; + } +} + +OXMTLV* SetFieldAction::field() { + return this->field_; +} + +size_t SetFieldAction::pack(uint8_t* buffer) { + size_t padding = ROUND_UP(this->field_->length(), 8) + - this->field_->length(); + Action::pack(buffer); + this->field_->pack( + buffer + (sizeof(struct of13::ofp_action_set_field) - 4)); + memset( + buffer + sizeof(struct of13::ofp_action_set_field) + + this->field_->length(), 0x0, padding); + return 0; +} + +of_error SetFieldAction::unpack(uint8_t *buffer) { + uint8_t * p = buffer + sizeof(struct of13::ofp_action_set_field) - 4; + size_t padding; + Action::unpack(buffer); + uint32_t header = ntoh32(*((uint32_t*) p)); + this->field_ = of13::Match::make_oxm_tlv(this->field_->oxm_field(header)); + this->field_->unpack(p); + return 0; +} + +PushPBBAction::PushPBBAction() + : set_order_(90), + Action(of13::OFPAT_PUSH_PBB, sizeof(struct of13::ofp_action_push)) { +} + +PushPBBAction::PushPBBAction(uint16_t ethertype) + : set_order_(90), + Action(of13::OFPAT_PUSH_PBB, sizeof(struct of13::ofp_action_push)) { + this->ethertype_ = ethertype; +} + +bool PushPBBAction::equals(const Action &other) { + + if (const PushPBBAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushPBBAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushPBBAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopPBBAction::PopPBBAction() + : set_order_(50), + Action(of13::OFPAT_POP_PBB, sizeof(struct of13::ofp_action_push)) { +} + +size_t PopPBBAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error PopPBBAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +ExperimenterAction::ExperimenterAction() + : Action(of13::OFPAT_EXPERIMENTER, + sizeof(struct of13::ofp_action_experimenter_header)) { +} + +ExperimenterAction::ExperimenterAction(uint32_t experimenter) + : Action(of13::OFPAT_EXPERIMENTER, + sizeof(struct of13::ofp_action_experimenter_header)) { + this->experimenter_ = experimenter; +} + +bool ExperimenterAction::equals(const Action &other) { + + if (const ExperimenterAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) + && (this->experimenter_ == act->experimenter_)); + } + else { + return false; + } +} + +size_t ExperimenterAction::pack(uint8_t* buffer) { + struct ofp_action_experimenter_header * ae = + (struct ofp_action_experimenter_header*) buffer; + Action::pack(buffer); + ae->experimenter = hton32(this->experimenter_); + return 0; +} + +of_error ExperimenterAction::unpack(uint8_t *buffer) { + struct ofp_action_experimenter_header * ae = + (struct ofp_action_experimenter_header*) buffer; + Action::unpack(buffer); + this->experimenter_ = ntoh32(ae->experimenter); + return 0; +} + +} //End of namespace of13 + +Action * Action::make_of13_action(uint16_t type) { + switch (type) { + case (of13::OFPAT_OUTPUT): { + return new of13::OutputAction(); + } + case (of13::OFPAT_COPY_TTL_OUT): { + return new of13::CopyTTLOutAction(); + } + case (of13::OFPAT_COPY_TTL_IN): { + return new of13::CopyTTLInAction(); + } + case (of13::OFPAT_SET_MPLS_TTL): { + return new of13::SetMPLSTTLAction(); + } + case (of13::OFPAT_DEC_MPLS_TTL): { + return new of13::DecMPLSTTLAction(); + } + case (of13::OFPAT_PUSH_VLAN): { + return new of13::PushVLANAction(); + } + case (of13::OFPAT_POP_VLAN): { + return new of13::PopVLANAction(); + } + case (of13::OFPAT_PUSH_MPLS): { + return new of13::PushMPLSAction(); + } + case (of13::OFPAT_POP_MPLS): { + return new of13::PopMPLSAction(); + } + case (of13::OFPAT_SET_QUEUE): { + return new of13::SetQueueAction(); + } + case (of13::OFPAT_GROUP): { + return new of13::GroupAction(); + } + case (of13::OFPAT_SET_NW_TTL): { + return new of13::SetNWTTLAction(); + } + case (of13::OFPAT_DEC_NW_TTL): { + return new of13::DecNWTTLAction(); + } + case (of13::OFPAT_SET_FIELD): { + return new of13::SetFieldAction(); + } + case (of13::OFPAT_PUSH_PBB): { + return new of13::PushPBBAction(); + } + case (of13::OFPAT_POP_PBB): { + return new of13::PopPBBAction(); + } + case (of13::OFPAT_EXPERIMENTER): { + return new of13::ExperimenterAction(); + } + } + return NULL; +} + +} //End of namespace fluid_msg + diff --git a/src/ovs/libfluid-msg/of13/of13common.cc b/src/ovs/libfluid-msg/of13/of13common.cc new file mode 100644 index 00000000..7a20f288 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13common.cc @@ -0,0 +1,1337 @@ +#include "libfluid-msg/of13/of13common.hh" + +namespace fluid_msg { + +namespace of13 { + +HelloElem::HelloElem(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool HelloElem::operator==(const HelloElem &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool HelloElem::operator!=(const HelloElem &other) const { + return !(*this == other); +} + +HelloElemVersionBitmap::HelloElemVersionBitmap(std::list bitmaps) + : HelloElem(of13::OFPHET_VERSIONBITMAP, + sizeof(struct of13::ofp_hello_elem_versionbitmap)) { + this->bitmaps_ = bitmaps; + this->length_ += bitmaps.size() * sizeof(uint32_t); +} + +bool HelloElemVersionBitmap::operator==( + const HelloElemVersionBitmap &other) const { + return ((HelloElem::operator==(other)) && (this->bitmaps_ == other.bitmaps_)); +} + +bool HelloElemVersionBitmap::operator!=( + const HelloElemVersionBitmap &other) const { + return !(*this == other); +} + +void HelloElemVersionBitmap::add_bitmap(uint32_t bitmap) { + this->bitmaps_.push_back(bitmap); + this->length_ += sizeof(uint32_t); +} + +size_t HelloElemVersionBitmap::pack(uint8_t* buffer) { + struct of13::ofp_hello_elem_versionbitmap *elem = + (struct of13::ofp_hello_elem_versionbitmap *) buffer; + elem->type = hton16(this->type_); + elem->length = hton16(this->length_); + uint8_t *p = buffer + sizeof(struct of13::ofp_hello_elem_versionbitmap); + for (std::list::iterator it = this->bitmaps_.begin(); + it != this->bitmaps_.end(); it++) { + uint32_t bitmap = hton32(*it); + memcpy(p, &bitmap, sizeof(uint32_t)); + p += sizeof(uint32_t); + } + return 0; +} + +of_error HelloElemVersionBitmap::unpack(uint8_t* buffer) { + struct of13::ofp_hello_elem_versionbitmap *elem = + (struct of13::ofp_hello_elem_versionbitmap *) buffer; + this->type_ = ntoh16(elem->type); + this->length_ = ntoh16(elem->length); + uint32_t bitmaps; + memcpy(&bitmaps, elem->bitmaps, sizeof(uint32_t)); + uint8_t *p = buffer + sizeof(struct of13::ofp_hello_elem_versionbitmap); + size_t len = this->length_ + - sizeof(struct of13::ofp_hello_elem_versionbitmap); + while (len) { + uint32_t bitmap = ntoh32((*(uint32_t*) p)); + this->bitmaps_.push_back(bitmap); + p += sizeof(uint32_t); + len -= sizeof(uint32_t); + } + return 0; +} + +Port::Port() + : PortCommon(), + port_no_(0), + curr_speed_(0), + max_speed_(0) { +} + +Port::Port(uint32_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer, uint32_t curr_speed, uint32_t max_speed) + : PortCommon(hw_addr, name, config, state, curr, advertised, supported, + peer), + port_no_(port_no), + curr_speed_(curr_speed), + max_speed_(max_speed) { +} + +bool Port::operator==(const Port &other) const { + return ((PortCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->curr_speed_ == other.curr_speed_) + && (this->max_speed_ == other.max_speed_)); +} + +bool Port::operator!=(const Port &other) const { + return !(*this == other); +} + +size_t Port::pack(uint8_t* buffer) { + struct of13::ofp_port *port = (struct of13::ofp_port*) buffer; + port->port_no = hton32(this->port_no_); + memset(port->pad, 0x0, 4); + memcpy(port->hw_addr, this->hw_addr_.get_data(), OFP_ETH_ALEN); + memset(port->pad2, 0x0, 2); + memset(port->name, 0x0, OFP_MAX_PORT_NAME_LEN); + memcpy(port->name, this->name_.c_str(), + this->name_.size() < OFP_MAX_PORT_NAME_LEN ? + this->name_.size() : OFP_MAX_PORT_NAME_LEN); + port->config = hton32(this->config_); + port->state = hton32(this->state_); + port->curr = hton32(this->curr_); + port->advertised = hton32(this->advertised_); + port->supported = hton32(this->supported_); + port->peer = hton32(this->peer_); + port->curr_speed = hton32(this->curr_speed_); + port->max_speed = hton32(this->max_speed_); + return 0; +} + +of_error Port::unpack(uint8_t* buffer) { + struct of13::ofp_port *port = (struct of13::ofp_port*) buffer; + this->port_no_ = ntoh32(port->port_no); + this->hw_addr_ = EthAddress(port->hw_addr); + this->name_ = std::string(port->name); + this->config_ = ntoh32(port->config); + this->state_ = ntoh32(port->state); + this->curr_ = ntoh32(port->curr); + this->advertised_ = ntoh32(port->advertised); + this->supported_ = ntoh32(port->supported); + this->peer_ = ntoh32(port->peer); + this->curr_speed_ = ntoh32(port->curr_speed); + this->max_speed_ = ntoh32(port->max_speed); + return 0; +} + +QueuePropMinRate::QueuePropMinRate(uint16_t rate) + : QueuePropRate(of13::OFPQT_MIN_RATE, rate) { + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +bool QueuePropMinRate::equals(const QueueProperty &other) { + if (const QueuePropMinRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMinRate::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMinRate::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +QueuePropMaxRate::QueuePropMaxRate(uint16_t rate) + : QueuePropRate(of13::OFPQT_MAX_RATE, rate) { + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +bool QueuePropMaxRate::equals(const QueueProperty &other) { + if (const QueuePropMaxRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMaxRate::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMaxRate::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +QueueExperimenter::QueueExperimenter(uint32_t experimenter) + : QueueProperty(of13::OFPQT_EXPERIMENTER) { + this->experimenter_ = experimenter; + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +size_t QueueExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_experimenter *qp = + (struct of13::ofp_queue_prop_experimenter *) buffer; + QueueProperty::pack(buffer); + qp->experimenter = hton32(this->experimenter_); + memset(qp->pad, 0x0, 4); + return this->len_; +} + +of_error QueueExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_experimenter *qp = + (struct of13::ofp_queue_prop_experimenter *) buffer; + QueueProperty::unpack(buffer); + this->experimenter_ = ntoh32(qp->experimenter); + return 0; +} + +PacketQueue::PacketQueue() + : PacketQueueCommon(), + port_(0) { + this->len_ = sizeof(struct of13::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, uint32_t port) + : PacketQueueCommon(queue_id) { + this->port_ = port; + this->len_ = sizeof(struct of13::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, uint32_t port, + QueuePropertyList properties) + : PacketQueueCommon(queue_id) { + this->port_ = port; + this->properties_ = properties; + this->len_ = sizeof(struct of13::ofp_packet_queue) + properties.length(); +} + +bool PacketQueue::operator==(const PacketQueue &other) const { + return ((PacketQueueCommon::operator==(other)) + && (this->port_ == other.port_)); +} + +bool PacketQueue::operator!=(const PacketQueue &other) const { + return !(*this == other); +} + +size_t PacketQueue::pack(uint8_t* buffer) { + struct of13::ofp_packet_queue *pq = (struct of13::ofp_packet_queue*) buffer; + pq->queue_id = hton32(this->queue_id_); + pq->port = hton32(this->port_); + pq->len = hton16(this->len_); + memset(pq->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_queue); + this->properties_.pack(p); + return this->len_; +} + +of_error PacketQueue::unpack(uint8_t* buffer) { + struct of13::ofp_packet_queue *pq = (struct of13::ofp_packet_queue*) buffer; + this->queue_id_ = ntoh32(pq->queue_id); + this->port_ = ntoh32(pq->port); + this->len_ = ntoh16(pq->len); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_queue); + this->properties_.length( + this->len_ - sizeof(struct of13::ofp_packet_queue)); + this->properties_.unpack13(p); + return 0; +} + +Bucket::Bucket() + : length_(sizeof(struct of13::ofp_bucket)), + weight_(0), + watch_port_(0), + watch_group_(0) { +} + +Bucket::Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group) { + this->weight_ = weight; + this->watch_port_ = watch_port; + this->watch_group_ = watch_group; + this->length_ = sizeof(struct of13::ofp_bucket); +} + +Bucket::Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group, + ActionSet actions) { + this->weight_ = weight; + this->watch_port_ = watch_port; + this->watch_group_ = watch_group; + this->actions_ = actions; + this->length_ = sizeof(struct of13::ofp_bucket) + actions.length(); +} + +bool Bucket::operator==(const Bucket &other) const { + return ((this->length_ == other.length_) && (this->weight_ == other.weight_) + && (this->watch_port_ == other.watch_port_) + && (this->watch_group_ == other.watch_group_) + && (this->actions_ == other.actions_)); +} + +bool Bucket::operator!=(const Bucket &other) const { + return !(*this == other); +} + +void Bucket::actions(ActionSet actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void Bucket::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void Bucket::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t Bucket::pack(uint8_t* buffer) { + struct of13::ofp_bucket *b = (struct of13::ofp_bucket*) buffer; + b->len = hton16(this->length_); + b->weight = hton16(this->weight_); + b->watch_port = hton32(this->watch_port_); + b->watch_group = hton32(this->watch_group_); + memset(b->pad, 0x0, 4); + this->actions_.pack(buffer + sizeof(struct of13::ofp_bucket)); + return 0; +} + +of_error Bucket::unpack(uint8_t* buffer) { + struct of13::ofp_bucket *b = (struct of13::ofp_bucket*) buffer; + this->length_ = ntoh16(b->len); + this->weight_ = ntoh16(b->weight); + this->watch_port_ = ntoh32(b->watch_port); + this->watch_group_ = ntoh32(b->watch_group); + this->actions_.length(this->length_ - sizeof(struct of13::ofp_bucket)); + this->actions_.unpack(buffer + sizeof(struct of13::ofp_bucket)); + return 0; +} + +FlowStats::FlowStats() + : FlowStatsCommon(), + flags_(0) { + this->length_ = sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match); +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t flags, uint64_t cookie, + uint64_t packet_count, uint64_t byte_count) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + this->flags_ = flags; + this->length_ = sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match); +} + +bool FlowStats::operator==(const FlowStats &other) const { + return ((FlowStatsCommon::operator==(other)) + && (this->flags_ == other.flags_) + && (this->instructions_ == other.instructions_) + && (this->match_ == other.match_)); +} + +bool FlowStats::operator!=(const FlowStats &other) const { + return !(*this == other); +} + +size_t FlowStats::pack(uint8_t* buffer) { + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_flow_stats) - sizeof(struct of13::ofp_match) + + this->match_.length(), 8) + - (sizeof(struct of13::ofp_flow_stats) - sizeof(struct of13::ofp_match) + + this->match_.length()); + struct of13::ofp_flow_stats *fs = (struct of13::ofp_flow_stats*) buffer; + fs->length = hton16(this->length_); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->duration_sec = hton32(this->duration_sec_); + fs->duration_nsec = hton32(this->duration_nsec_); + fs->priority = hton16(this->priority_); + fs->idle_timeout = hton16(this->idle_timeout_); + fs->hard_timeout = hton16(this->hard_timeout_); + fs->flags = hton16(this->flags_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->packet_count = hton64(this->packet_count_); + fs->byte_count = hton64(this->byte_count_); + uint8_t *p = + buffer + + (sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + p += padding; + this->instructions_.pack(p); + return this->length_; +} + +of_error FlowStats::unpack(uint8_t* buffer) { + struct of13::ofp_flow_stats *fs = (struct of13::ofp_flow_stats*) buffer; + this->length_ = ntoh16(fs->length); + this->table_id_ = fs->table_id; + this->duration_sec_ = ntoh32(fs->duration_sec); + this->duration_nsec_ = ntoh32(fs->duration_nsec); + this->priority_ = ntoh16(fs->priority); + this->idle_timeout_ = ntoh16(fs->idle_timeout); + this->hard_timeout_ = ntoh16(fs->hard_timeout); + this->flags_ = ntoh16(fs->flags); + this->cookie_ = ntoh64(fs->cookie); + this->packet_count_ = ntoh64(fs->packet_count); + this->byte_count_ = ntoh64(fs->byte_count); + uint8_t *p = + buffer + + (sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + this->instructions_.length( + this->length_ + - ((sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)) + + ROUND_UP(this->match_.length(), 8))); + p += ROUND_UP(this->match_.length(), 8); + this->instructions_.unpack(p); + return 0; +} + +void FlowStats::match(of13::Match match) { + this->match_ = match; + this->length_ += match.length(); + //Padding bytes + this->length_ = ROUND_UP(this->length_, 8); +} + +OXMTLV * FlowStats::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void FlowStats::instructions(InstructionSet instructions) { + this->instructions_ = instructions; + this->length_ += instructions.length(); +} + +void FlowStats::add_instruction(Instruction* inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst->length(); +} + +TableStats::TableStats() + : TableStatsCommon() { +} + +TableStats::TableStats(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count) + : TableStatsCommon(table_id, active_count, lookup_count, matched_count) { +} + +size_t TableStats::pack(uint8_t* buffer) { + struct of13::ofp_table_stats *ts = (struct of13::ofp_table_stats*) buffer; + ts->table_id = this->table_id_; + memset(ts->pad, 0x0, 3); + ts->active_count = hton32(this->active_count_); + ts->lookup_count = hton64(this->lookup_count_); + ts->matched_count = hton64(this->matched_count_); + return 0; +} + +of_error TableStats::unpack(uint8_t* buffer) { + struct of13::ofp_table_stats *ts = (struct of13::ofp_table_stats*) buffer; + this->table_id_ = ts->table_id; + this->active_count_ = ntoh32(ts->active_count); + this->lookup_count_ = ntoh64(ts->lookup_count); + this->matched_count_ = ntoh64(ts->matched_count); + return 0; +} + +PortStats::PortStats() + : PortStatsCommon(), + port_no_(0), + duration_sec_(0), + duration_nsec_(0) { +} + +PortStats::PortStats(uint32_t port_no, struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions, uint32_t duration_sec, + uint32_t duration_nsec) + : PortStatsCommon(rx_tx_stats, err_stats, collisions) { + this->port_no_ = port_no; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; +} + +bool PortStats::operator==(const PortStats &other) const { + return ((PortStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} + +bool PortStats::operator!=(const PortStats &other) const { + return !(*this == other); +} + +size_t PortStats::pack(uint8_t* buffer) { + struct of13::ofp_port_stats *ps = (struct of13::ofp_port_stats*) buffer; + ps->port_no = hton32(this->port_no_); + memset(ps->pad, 0x0, 6); + PortStatsCommon::pack(buffer + 8); + ps->collisions = hton64(this->collisions_); + ps->duration_sec = hton32(this->duration_sec_); + ps->duration_nsec = hton32(this->duration_nsec_); + return 0; +} + +of_error PortStats::unpack(uint8_t* buffer) { + struct of13::ofp_port_stats *ps = (struct of13::ofp_port_stats*) buffer; + this->port_no_ = ntoh32(ps->port_no); + PortStatsCommon::unpack(buffer + 8); + this->collisions_ = ntoh64(ps->collisions); + this->duration_sec_ = hton32(ps->duration_sec); + this->duration_nsec_ = hton32(ps->duration_nsec); + return 0; +} + +QueueStats::QueueStats() + : QueueStatsCommon(), + port_no_(0), + duration_sec_(0), + duration_nsec_(0) { + +} + +QueueStats::QueueStats(uint32_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors, uint32_t duration_sec, + uint32_t duration_nsec) + : QueueStatsCommon(queue_id, tx_bytes, tx_packets, tx_errors) { + this->port_no_ = port_no; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; +} + +bool QueueStats::operator==(const QueueStats &other) const { + return ((QueueStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} +bool QueueStats::operator!=(const QueueStats &other) const { + return !(*this == other); +} + +size_t QueueStats::pack(uint8_t* buffer) { + struct of13::ofp_queue_stats *qs = (struct of13::ofp_queue_stats*) buffer; + qs->port_no = hton32(this->port_no_); + qs->queue_id = hton32(this->queue_id_); + qs->tx_bytes = hton64(this->tx_bytes_); + qs->tx_packets = hton64(this->tx_packets_); + qs->tx_errors = hton64(this->tx_errors_); + qs->duration_sec = hton32(this->duration_sec_); + qs->duration_nsec = hton32(this->duration_nsec_); + return 0; +} + +of_error QueueStats::unpack(uint8_t* buffer) { + struct of13::ofp_queue_stats *qs = (struct of13::ofp_queue_stats*) buffer; + this->port_no_ = ntoh32(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + this->tx_bytes_ = ntoh64(qs->tx_bytes); + this->tx_packets_ = ntoh64(qs->tx_packets); + this->tx_errors_ = ntoh64(qs->tx_errors); + this->duration_sec_ = ntoh32(qs->duration_sec); + this->duration_nsec_ = ntoh32(qs->duration_nsec); + return 0; +} + +BucketStats::BucketStats() + : packet_count_(0), + byte_count_(0) { + +} + +BucketStats::BucketStats(uint64_t packet_count, uint64_t byte_count) { + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; +} + +bool BucketStats::operator==(const BucketStats &other) const { + return ((this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool BucketStats::operator!=(const BucketStats &other) const { + return !(*this == other); +} + +size_t BucketStats::pack(uint8_t* buffer) { + struct of13::ofp_bucket_counter *bc = + (struct of13::ofp_bucket_counter *) buffer; + bc->packet_count = hton64(this->packet_count_); + bc->byte_count = hton64(this->byte_count_); + return 0; +} + +of_error BucketStats::unpack(uint8_t* buffer) { + struct of13::ofp_bucket_counter *bc = + (struct of13::ofp_bucket_counter *) buffer; + this->packet_count_ = ntoh64(bc->packet_count); + this->byte_count_ = ntoh64(bc->byte_count); + return 0; +} + +GroupStats::GroupStats(uint32_t group_id, uint32_t ref_count, + uint64_t packet_count, uint64_t byte_count, uint32_t duration_sec, + uint32_t duration_nsec) { + this->group_id_ = group_id; + this->ref_count_ = ref_count; + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->length_ = sizeof(struct of13::ofp_group_stats); +} + +GroupStats::GroupStats(uint32_t group_id, uint32_t ref_count, + uint64_t packet_count, uint64_t byte_count, uint32_t duration_sec, + uint32_t duration_nsec, std::vector bucket_stats) { + this->group_id_ = group_id; + this->ref_count_ = ref_count; + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->bucket_stats_ = bucket_stats; + this->length_ = sizeof(struct of13::ofp_group_stats) + + bucket_stats.size() * sizeof(struct of13::ofp_bucket_counter); +} + +bool GroupStats::operator==(const GroupStats &other) const { + return ((this->group_id_ == other.group_id_) + && (this->ref_count_ == other.ref_count_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->bucket_stats_ == other.bucket_stats_) + && (this->length_ == other.length_)); +} + +bool GroupStats::operator!=(const GroupStats &other) const { + return !(*this == other); +} + +size_t GroupStats::pack(uint8_t* buffer) { + struct of13::ofp_group_stats *gs = (struct of13::ofp_group_stats *) buffer; + gs->length = hton16(this->length_); + gs->group_id = hton32(this->group_id_); + gs->ref_count = hton32(this->ref_count_); + gs->packet_count = hton64(this->packet_count_); + gs->byte_count = hton64(this->byte_count_); + gs->duration_sec = hton32(this->duration_sec_); + gs->duration_nsec = hton32(this->duration_nsec_); + uint8_t *p = buffer + sizeof(of13::ofp_group_stats); + for (std::vector::iterator it = this->bucket_stats_.begin(); + it != this->bucket_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_bucket_counter); + } + return 0; +} + +of_error GroupStats::unpack(uint8_t* buffer) { + struct of13::ofp_group_stats *gs = (struct of13::ofp_group_stats *) buffer; + this->length_ = ntoh16(gs->length); + this->group_id_ = ntoh32(gs->group_id); + this->ref_count_ = ntoh32(gs->ref_count); + this->packet_count_ = ntoh64(gs->packet_count); + this->byte_count_ = ntoh64(gs->byte_count); + this->duration_sec_ = ntoh32(gs->duration_sec); + this->duration_nsec_ = ntoh32(gs->duration_nsec); + uint8_t *p = buffer + sizeof(of13::ofp_group_stats); + size_t len = this->length_ - sizeof(of13::ofp_group_stats); + while (len) { + BucketStats stats; + stats.unpack(p); + this->bucket_stats_.push_back(stats); + p += sizeof(struct of13::ofp_bucket_counter); + len -= sizeof(struct of13::ofp_bucket_counter); + } + return 0; +} + +void GroupStats::bucket_stats(std::vector bucket_stats) { + this->bucket_stats_ = bucket_stats; + this->length_ += bucket_stats.size() + * sizeof(struct of13::ofp_bucket_counter); +} +void GroupStats::add_bucket_stat(BucketStats stat) { + this->bucket_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_bucket_counter); +} + +GroupDesc::GroupDesc(uint8_t type, uint32_t group_id) { + this->type_ = type; + this->group_id_ = group_id; + this->length_ = sizeof(struct of13::ofp_group_desc_stats); +} + +GroupDesc::GroupDesc(uint8_t type, uint32_t group_id, + std::vector buckets) { + this->type_ = type; + this->group_id_ = group_id; + this->buckets_ = buckets; + this->length_ = sizeof(struct of13::ofp_group_desc_stats) + buckets_len(); +} + +bool GroupDesc::operator==(const GroupDesc &other) const { + return ((this->type_ == other.type_) && (this->group_id_ == other.group_id_) + && (this->length_ == other.length_) + && (this->buckets_ == other.buckets_)); +} + +bool GroupDesc::operator!=(const GroupDesc &other) const { + return !(*this == other); +} + +size_t GroupDesc::pack(uint8_t* buffer) { + struct of13::ofp_group_desc_stats * gd = + (struct of13::ofp_group_desc_stats *) buffer; + gd->length = hton16(this->length_); + gd->type = this->type_; + memset(&gd->pad, 0x0, 1); + gd->group_id = hton32(this->group_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_group_desc_stats); + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return this->length_; +} + +of_error GroupDesc::unpack(uint8_t* buffer) { + struct of13::ofp_group_desc_stats * gd = + (struct of13::ofp_group_desc_stats *) buffer; + this->length_ = ntoh16(gd->length); + this->type_ = gd->type; + this->group_id_ = ntoh32(gd->group_id); + size_t len = this->length_ - sizeof(struct of13::ofp_group_desc_stats); + uint8_t *p = buffer + sizeof(struct of13::ofp_group_desc_stats); + while (len) { + Bucket bucket; + bucket.unpack(p); + this->buckets_.push_back(bucket); + p += bucket.len(); + len -= bucket.len(); + } + return 0; +} + +void GroupDesc::buckets(std::vector buckets) { + this->buckets_ = buckets; + this->length_ += buckets_len(); +} + +void GroupDesc::add_bucket(Bucket bucket) { + this->buckets_.push_back(bucket); + this->length_ += bucket.len(); +} + +size_t GroupDesc::buckets_len() { + size_t len = 0; + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + len += it->len(); + } + return len; +} +; + +GroupFeatures::GroupFeatures(uint32_t types, uint32_t capabilities, + uint32_t max_groups[4], uint32_t actions[4]) { + this->types_ = types; + this->capabilities_ = capabilities; + memcpy(this->max_groups_, max_groups, 16); + memcpy(this->actions_, actions, 16); +} + +bool GroupFeatures::operator==(const GroupFeatures &other) const { + for (int i = 0; i < 4; i++) { + if (this->max_groups_[i] != other.max_groups_[i]) { + return false; + } + if (this->actions_[i] != other.actions_[i]) { + return false; + } + } + return ((this->types_ == other.types_) + && (this->capabilities_ == other.capabilities_)); +} + +bool GroupFeatures::operator!=(const GroupFeatures &other) const { + return !(*this == other); +} + +size_t GroupFeatures::pack(uint8_t* buffer) { + struct of13::ofp_group_features *gf = + (struct of13::ofp_group_features*) buffer; + gf->types = hton32(this->types_); + gf->capabilities = hton32(this->capabilities_); + for (int i = 0; i < 4; i++) { + gf->max_groups[i] = hton32(this->max_groups_[i]); + gf->actions[i] = hton32(this->actions_[i]); + } + return 0; +} + +of_error GroupFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_group_features *gf = + (struct of13::ofp_group_features*) buffer; + this->types_ = ntoh32(gf->types); + this->capabilities_ = ntoh32(gf->capabilities); + for (int i = 0; i < 4; i++) { + this->max_groups_[i] = ntoh32(gf->max_groups[i]); + this->actions_[i] = ntoh32(gf->actions[i]); + } + return 0; +} + +TableFeatureProp::TableFeatureProp(uint16_t type) { + this->type_ = type; + this->length_ = sizeof(struct of13::ofp_table_feature_prop_header); + this->padding_ = ROUND_UP( + sizeof(struct of13::ofp_table_feature_prop_header), 8) + - sizeof(struct of13::ofp_table_feature_prop_header); +} + +bool TableFeatureProp::equals(const TableFeatureProp &other) { + return ((*this == other)); +} + +bool TableFeatureProp::operator==(const TableFeatureProp &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool TableFeatureProp::operator!=(const TableFeatureProp &other) const { + return !(*this == other); +} + +size_t TableFeatureProp::pack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_header *fp = + (struct of13::ofp_table_feature_prop_header*) buffer; + fp->type = hton16(this->type_); + fp->length = hton16(this->length_); + return 0; +} + +of_error TableFeatureProp::unpack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_header *fp = + (struct of13::ofp_table_feature_prop_header*) buffer; + this->type_ = ntoh16(fp->type); + this->length_ = ntoh16(fp->length); + return 0; +} + +TableFeaturePropInstruction::TableFeaturePropInstruction(uint16_t type, + std::vector instruction_ids) + : TableFeatureProp(type) { + this->instruction_ids_ = instruction_ids; + this->length_ += instruction_ids.size() + * sizeof(struct of13::ofp_instruction); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropInstruction::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropInstruction * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->instruction_ids_ == prop->instruction_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropInstruction::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->instruction_ids_.begin(); + it != this->instruction_ids_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_instruction); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropInstruction::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + Instruction inst; + while (len) { + inst.unpack(p); + this->instruction_ids_.push_back(inst); + p += sizeof(struct of13::ofp_instruction); + len -= sizeof(struct of13::ofp_instruction); + } + return 0; +} + +void TableFeaturePropInstruction::instruction_ids( + std::vector instruction_ids) { + this->instruction_ids_ = instruction_ids; + //Total length with padding + this->length_ += instruction_ids.size() + * sizeof(struct of13::ofp_instruction); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropNextTables::TableFeaturePropNextTables(uint16_t type, + std::vector next_table_ids) + : TableFeatureProp(type) { + this->next_table_ids_ = next_table_ids_; + this->length_ += next_table_ids_.size(); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropNextTables::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropNextTables * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->next_table_ids_ == prop->next_table_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropNextTables::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->next_table_ids_.begin(); + it != this->next_table_ids_.end(); ++it) { + memcpy(p, &(*it), sizeof(uint8_t)); + p += sizeof(uint8_t); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropNextTables::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + while (len) { + this->next_table_ids_.push_back(*p); + p += sizeof(uint8_t); + len -= sizeof(uint8_t); + } + return 0; +} + +void TableFeaturePropNextTables::table_ids( + std::vector next_table_ids) { + this->next_table_ids_ = next_table_ids; + this->length_ += next_table_ids_.size() * sizeof(uint8_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropActions::TableFeaturePropActions(uint16_t type, + std::vector action_ids) + : TableFeatureProp(type) { + this->action_ids_ = action_ids; + this->length_ += action_ids.size() * sizeof(struct ofp_action_header); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropActions::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropActions * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->action_ids_ == prop->action_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropActions::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->action_ids_.begin(); + it != this->action_ids_.end(); ++it) { + it->pack(p); + p += sizeof(struct ofp_action_header); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropActions::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + Action act; + while (len) { + act.unpack(p); + this->action_ids_.push_back(act); + p += sizeof(struct ofp_action_header); + len -= sizeof(struct ofp_action_header); + } + return 0; +} + +void TableFeaturePropActions::action_ids(std::vector action_ids) { + this->action_ids_ = action_ids; + this->length_ += action_ids.size() * sizeof(struct ofp_action_header); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropOXM::TableFeaturePropOXM(uint16_t type, + std::vector oxm_ids) + : TableFeatureProp(type) { + this->oxm_ids_ = oxm_ids; + this->length_ += oxm_ids_.size() * sizeof(uint32_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropOXM::equals(const TableFeatureProp &other) { + if (const TableFeaturePropOXM * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->oxm_ids_ == prop->oxm_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropOXM::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->oxm_ids_.begin(); + it != this->oxm_ids_.end(); ++it) { + memcpy(p, &(*it), sizeof(uint32_t)); + p += sizeof(uint32_t); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropOXM::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + while (len) { + uint32_t *oxm_id = (uint32_t*) p; + this->oxm_ids_.push_back(*oxm_id); + p += sizeof(uint32_t); + len -= sizeof(uint32_t); + } + return 0; +} + +void TableFeaturePropOXM::oxm_ids(std::vector oxm_ids) { + this->oxm_ids_ = oxm_ids; + this->length_ += oxm_ids_.size() * sizeof(uint32_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropExperimenter::TableFeaturePropExperimenter(uint16_t type, + uint32_t experimenter, uint32_t exp_type) + : TableFeatureProp(type) { + this->experimenter_ = experimenter; + this->exp_type_ = exp_type; + this->length_ += sizeof(struct of13::ofp_table_feature_prop_experimenter); +} + +bool TableFeaturePropExperimenter::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropExperimenter * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->experimenter_ == prop->experimenter_) + && (this->exp_type_ == prop->exp_type_)); + } + else { + return false; + } +} + +size_t TableFeaturePropExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_experimenter *pe = + (struct of13::ofp_table_feature_prop_experimenter*) buffer; + TableFeatureProp::pack(buffer); + pe->experimenter = hton32(this->experimenter_); + pe->exp_type = hton32(this->exp_type_); + return 0; +} + +of_error TableFeaturePropExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_experimenter *pe = + (struct of13::ofp_table_feature_prop_experimenter*) buffer; + TableFeatureProp::unpack(buffer); + this->experimenter_ = ntoh32(pe->experimenter); + this->exp_type_ = ntoh32(pe->exp_type); + return 0; +} + +TablePropertiesList::TablePropertiesList( + std::list property_list) { + this->property_list_ = property_list_; + for (std::list::const_iterator it = + property_list.begin(); it != property_list.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +TablePropertiesList::TablePropertiesList(const TablePropertiesList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = + other.property_list_.begin(); it != other.property_list_.end(); ++it) { + this->property_list_.push_back((*it)->clone()); + } +} + +TablePropertiesList::~TablePropertiesList() { + this->property_list_.remove_if(TableFeatureProp::delete_all); +} + +bool TablePropertiesList::operator==(const TablePropertiesList &other) const { + std::list::const_iterator ot = + other.property_list_.begin(); + for (std::list::const_iterator it = + this->property_list_.begin(); it != this->property_list_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool TablePropertiesList::operator!=(const TablePropertiesList &other) const { + return !(*this == other); +} + +size_t TablePropertiesList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = + this->property_list_.begin(), end = this->property_list_.end(); + it != end; it++) { + (*it)->pack(p); + p += (*it)->length() + (*it)->padding(); + } + return 0; +} + +of_error TablePropertiesList::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + TableFeatureProp *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = TableFeatures::make_table_feature_prop(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->length() + prop->padding(); + p += prop->length() + prop->padding(); + } + return 0; +} + +TablePropertiesList& TablePropertiesList::operator=(TablePropertiesList other) { + swap(*this, other); + return *this; +} + +void swap(TablePropertiesList& first, TablePropertiesList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.property_list_, second.property_list_); +} + +void TablePropertiesList::property_list( + std::list property_list) { + this->property_list_ = property_list; + for (std::list::const_iterator it = + property_list.begin(); it != property_list.end(); ++it) { + this->length_ += (*it)->length() + (*it)->padding(); + } +} + +void TablePropertiesList::add_property(TableFeatureProp* prop) { + this->property_list_.push_back(prop); + this->length_ = prop->length() + prop->padding(); +} + +TableFeatures::TableFeatures(uint8_t table_id, std::string name, + uint64_t metadata_match, uint64_t metadata_write, uint32_t config, + uint32_t max_entries) + : table_id_(table_id), + name_(name), + metadata_match_(metadata_match), + metadata_write_(metadata_write), + config_(config), + max_entries_(max_entries) { + this->length_ = sizeof(struct of13::ofp_table_features); +} + +bool TableFeatures::operator==(const TableFeatures &other) const { + return ((this->length_ == other.length_) + && (this->table_id_ == other.table_id_) && (this->name_ == other.name_) + && (this->metadata_match_ == other.metadata_match_) + && (this->metadata_write_ == other.metadata_write_) + && (this->config_ == other.config_) + && (this->max_entries_ == other.max_entries_) + && (this->properties_ == other.properties_)); +} + +bool TableFeatures::operator!=(const TableFeatures &other) const { + return !(*this == other); +} + +uint16_t TableFeatures::length() { + //Return padded len + return ROUND_UP(this->length_, 8); +} + +size_t TableFeatures::pack(uint8_t* buffer) { + struct of13::ofp_table_features *tf = + (struct of13::ofp_table_features*) buffer; + tf->length = hton16(length()); + tf->table_id = this->table_id_; + memset(tf->pad, 0x0, 5); + memset(tf->name, 0x0, OFP_FLUID_MAX_TABLE_NAME_LEN); + memcpy(tf->name, this->name_.c_str(), + this->name_.size() < OFP_FLUID_MAX_TABLE_NAME_LEN ? + this->name_.size() : OFP_FLUID_MAX_TABLE_NAME_LEN); + tf->metadata_match = hton64(this->metadata_match_); + tf->metadata_write = hton64(this->metadata_write_); + tf->config = hton32(this->config_); + tf->max_entries = hton32(this->max_entries_); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_features); + this->properties_.pack(p); + return length(); +} + +of_error TableFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_table_features *tf = + (struct of13::ofp_table_features*) buffer; + this->length_ = ntoh16(tf->length); + this->table_id_ = tf->table_id; + this->name_ = std::string(tf->name); + this->metadata_match_ = ntoh64(tf->metadata_match); + this->metadata_write_ = ntoh64(tf->metadata_write); + this->config_ = ntoh32(tf->config); + this->max_entries_ = ntoh32(tf->max_entries); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_features); + this->properties_.length( + this->length_ - sizeof(struct of13::ofp_table_features)); + this->properties_.unpack(p); + return 0; +} + +void TableFeatures::properties(TablePropertiesList properties) { + this->properties_ = properties; + this->length_ += properties.length(); + +} + +void TableFeatures::add_table_prop(TableFeatureProp* prop) { + this->properties_.add_property(prop); + this->length_ += prop->length() + prop->padding(); +} + +TableFeatureProp* TableFeatures::make_table_feature_prop(uint16_t type) { + if (type == OFPTFPT_INSTRUCTIONS || type == OFPTFPT_INSTRUCTIONS_MISS) { + return new TableFeaturePropInstruction(type); + } + if (type == OFPTFPT_NEXT_TABLES || type == OFPTFPT_NEXT_TABLES_MISS) { + return new TableFeaturePropNextTables(type); + } + if (type == OFPTFPT_WRITE_ACTIONS || type == OFPTFPT_WRITE_ACTIONS_MISS + || type == OFPTFPT_APPLY_ACTIONS + || type == OFPTFPT_APPLY_ACTIONS_MISS) { + return new TableFeaturePropActions(type); + } + if (type == OFPTFPT_MATCH || type == OFPTFPT_WILDCARDS + || type == OFPTFPT_WRITE_SETFIELD || type == OFPTFPT_WRITE_SETFIELD_MISS + || type == OFPTFPT_APPLY_SETFIELD + || type == OFPTFPT_APPLY_SETFIELD_MISS) { + return new TableFeaturePropOXM(type); + } + if (type == OFPTFPT_EXPERIMENTER || type == OFPTFPT_EXPERIMENTER_MISS) { + return new TableFeaturePropExperimenter(type); + } + return NULL; +} + +} //End of namespace fluid_msg + +QueueProperty* QueueProperty::make_queue_of13_property(uint16_t property) { + switch (property) { + case (of13::OFPQT_MAX_RATE): { + return new of13::QueuePropMaxRate(); + } + case (of13::OFPQT_MIN_RATE): { + return new of13::QueuePropMinRate(); + } + case (of13::OFPQT_EXPERIMENTER): { + return new of13::QueueExperimenter(); + } + } + return NULL; +} + +} //End namespace of13 diff --git a/src/ovs/libfluid-msg/of13/of13instruction.cc b/src/ovs/libfluid-msg/of13/of13instruction.cc new file mode 100644 index 00000000..087deeaa --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13instruction.cc @@ -0,0 +1,416 @@ +#include "libfluid-msg/of13/of13instruction.hh" + +namespace fluid_msg { + +namespace of13 { + +Instruction::Instruction() + : type_(0), + length_(0) { +} + +Instruction::Instruction(uint16_t type, uint16_t length) + : type_(type), + length_(length) { +} + +bool Instruction::equals(const Instruction &other) { + return (*this == other); +} + +bool Instruction::operator==(const Instruction &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool Instruction::operator!=(const Instruction &other) const { + return !(*this == other); +} + +InstructionSet::InstructionSet(std::set instruction_set) { + this->instruction_set_ = instruction_set_; + for (std::set::const_iterator it = instruction_set.begin(); + it != instruction_set.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +InstructionSet::InstructionSet(const InstructionSet &other) { + this->length_ = other.length_; + for (std::set::const_iterator it = + other.instruction_set_.begin(); it != other.instruction_set_.end(); + ++it) { + this->instruction_set_.insert((*it)->clone()); + } +} + +bool InstructionSet::operator==(const InstructionSet &other) const { + std::set::const_iterator ot = other.instruction_set_.begin(); + for (std::set::const_iterator it = + this->instruction_set_.begin(); it != this->instruction_set_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool InstructionSet::operator!=(const InstructionSet &other) const { + return !(*this == other); +} + +InstructionSet::~InstructionSet() { + for (std::set::const_iterator it = + this->instruction_set_.begin(); it != this->instruction_set_.end(); + ++it) { + delete *it; + } +} + +size_t InstructionSet::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::set::iterator it = this->instruction_set_.begin(), + end = this->instruction_set_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +of_error InstructionSet::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Instruction *inst; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + inst = Instruction::make_instruction(type); + inst->unpack(p); + this->instruction_set_.insert(inst); + len -= inst->length(); + p += inst->length(); + } + return 0; +} + +InstructionSet& InstructionSet::operator=(InstructionSet other) { + swap(*this, other); + return *this; +} + +void swap(InstructionSet& first, InstructionSet& second) { + + std::swap(first.length_, second.length_); + std::swap(first.instruction_set_, second.instruction_set_); +} + +void InstructionSet::add_instruction(Instruction &inst) { + Instruction* instp = inst.clone(); + this->instruction_set_.insert(instp); + this->length_ += inst.length(); +} + +void InstructionSet::add_instruction(Instruction *inst) { + this->instruction_set_.insert(inst); + this->length_ += inst->length(); +} + +Instruction* Instruction::make_instruction(uint16_t type) { + switch (type) { + case (of13::OFPIT_GOTO_TABLE): { + return new GoToTable(); + } + case (of13::OFPIT_WRITE_METADATA): { + return new WriteMetadata(); + } + case (of13::OFPIT_CLEAR_ACTIONS): { + return new ClearActions(); + } + case (of13::OFPIT_WRITE_ACTIONS): { + return new WriteActions(); + } + case (of13::OFPIT_APPLY_ACTIONS): { + return new ApplyActions(); + } + case (of13::OFPIT_METER): { + return new Meter(); + } + case (of13::OFPIT_EXPERIMENTER): { + return new InstructionExperimenter(); + } + } + return NULL; +} + +size_t Instruction::pack(uint8_t* buffer) { + struct of13::ofp_instruction *in = (struct of13::ofp_instruction *) buffer; + in->type = hton16(this->type_); + in->len = hton16(this->length_); + return 0; +} + +of_error Instruction::unpack(uint8_t* buffer) { + struct of13::ofp_instruction *in = (struct of13::ofp_instruction *) buffer; + this->type_ = ntoh16(in->type); + this->length_ = ntoh16(in->len); + return 0; +} + +GoToTable::GoToTable(uint8_t table_id) + : Instruction(of13::OFPIT_GOTO_TABLE, + sizeof(struct of13::ofp_instruction_goto_table)), + set_order_(60) { + this->table_id_ = table_id; +} + +bool GoToTable::equals(const Instruction &other) { + + if (const GoToTable * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->table_id_ == inst->table_id_)); + } + else { + return false; + } +} + +size_t GoToTable::pack(uint8_t* buffer) { + struct of13::ofp_instruction_goto_table *go = + (struct of13::ofp_instruction_goto_table *) buffer; + Instruction::pack(buffer); + go->table_id = this->table_id_; + memset(go->pad, 0x0, 3); + return 0; +} + +of_error GoToTable::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_goto_table *go = + (struct of13::ofp_instruction_goto_table *) buffer; + Instruction::unpack(buffer); + this->table_id_ = go->table_id; + return 0; +} + +WriteMetadata::WriteMetadata(uint64_t metadata, uint64_t metadata_mask) + : Instruction(of13::OFPIT_WRITE_METADATA, + sizeof(struct of13::ofp_instruction_write_metadata)), + set_order_(50) { + this->metadata_ = metadata; + this->metadata_mask_ = metadata_mask; +} + +bool WriteMetadata::equals(const Instruction &other) { + + if (const WriteMetadata * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->metadata_mask_ == inst->metadata_mask_)); + } + else { + return false; + } +} + +size_t WriteMetadata::pack(uint8_t* buffer) { + struct of13::ofp_instruction_write_metadata *wm = + (struct of13::ofp_instruction_write_metadata *) buffer; + Instruction::pack(buffer); + memset(wm->pad, 0x0, 4); + wm->metadata = hton64(this->metadata_); + wm->metadata_mask = hton64(this->metadata_mask_); + return 0; +} + +of_error WriteMetadata::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_write_metadata *wm = + (struct of13::ofp_instruction_write_metadata *) buffer; + Instruction::unpack(buffer); + this->metadata_ = ntoh64(wm->metadata); + this->metadata_mask_ = ntoh64(wm->metadata_mask); + return 0; +} + +WriteActions::WriteActions(ActionSet actions_) + : Instruction(of13::OFPIT_WRITE_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(40) { + actions(actions_); +} + +bool WriteActions::equals(const Instruction &other) { + if (const WriteActions * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->actions_ == inst->actions_)); + } + else { + return false; + } +} + +void WriteActions::actions(ActionSet actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void WriteActions::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void WriteActions::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t WriteActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction_actions *ia = + (struct of13::ofp_instruction_actions*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + uint8_t *p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.pack(p); + return 0; +} + +of_error WriteActions::unpack(uint8_t* buffer) { + Instruction::unpack(buffer); + uint8_t* p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.length( + this->length_ - sizeof(struct of13::ofp_instruction_actions)); + this->actions_.unpack(p); + return 0; +} + +ApplyActions::ApplyActions(ActionList actions_) + : Instruction(of13::OFPIT_APPLY_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(20) { + actions(actions_); +} + +bool ApplyActions::equals(const Instruction &other) { + if (const ApplyActions * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->actions_ == inst->actions_)); + } + else { + return false; + } +} + +void ApplyActions::actions(ActionList actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void ApplyActions::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void ApplyActions::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t ApplyActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction_actions *ia = + (struct of13::ofp_instruction_actions*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + uint8_t *p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.pack(p); + return 0; +} + +of_error ApplyActions::unpack(uint8_t* buffer) { + Instruction::unpack(buffer); + uint8_t* p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.length( + this->length_ - sizeof(struct of13::ofp_instruction_actions)); + this->actions_.unpack13(p); + return 0; +} + +size_t ClearActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction *ia = (struct of13::ofp_instruction*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + return 0; +} + +of_error ClearActions::unpack(uint8_t* buffer) { + struct of13::ofp_instruction *ia = (struct of13::ofp_instruction*) buffer; + Instruction::unpack(buffer); + return 0; +} + +Meter::Meter(uint32_t meter_id) + : Instruction(of13::OFPIT_METER, + sizeof(struct of13::ofp_instruction_meter)), + set_order_(10) { + this->meter_id_ = meter_id; +} + +bool Meter::equals(const Instruction &other) { + + if (const Meter * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->meter_id_ == inst->meter_id_)); + } + else { + return false; + } +} + +size_t Meter::pack(uint8_t* buffer) { + struct of13::ofp_instruction_meter *im = + (struct of13::ofp_instruction_meter *) buffer; + Instruction::pack(buffer); + im->meter_id = hton32(this->meter_id_); + return 0; +} + +of_error Meter::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_meter *im = + (struct of13::ofp_instruction_meter *) buffer; + Instruction::unpack(buffer); + this->meter_id_ = ntoh32(im->meter_id); + return 0; +} + +InstructionExperimenter::InstructionExperimenter(uint32_t experimenter) + : Instruction(of13::OFPIT_EXPERIMENTER, + sizeof(struct of13::ofp_instruction_experimenter)) { + this->experimenter_ = experimenter; +} + +bool InstructionExperimenter::equals(const Instruction &other) { + + if (const InstructionExperimenter * inst = + dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->experimenter_ == inst->experimenter_)); + } + else { + return false; + } +} + +size_t InstructionExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_instruction_experimenter *ie = + (struct of13::ofp_instruction_experimenter *) buffer; + Instruction::pack(buffer); + ie->experimenter = hton32(this->experimenter_); + return 0; +} + +of_error InstructionExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_experimenter *ie = + (struct of13::ofp_instruction_experimenter *) buffer; + Instruction::unpack(buffer); + this->experimenter_ = ntoh32(ie->experimenter); + return 0; +} + +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of13/of13match.cc b/src/ovs/libfluid-msg/of13/of13match.cc new file mode 100644 index 00000000..0194704c --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13match.cc @@ -0,0 +1,2733 @@ +#include "libfluid-msg/of13/of13match.hh" +#include +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +namespace of13 { + +MatchHeader::MatchHeader() + : type_(0), + length_(0) { +} + +MatchHeader::MatchHeader(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool MatchHeader::operator==(const MatchHeader &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool MatchHeader::operator!=(const MatchHeader &other) const { + return !(*this == other); +} + +size_t MatchHeader::pack(uint8_t *buffer) { + struct of13::ofp_match *m = (struct of13::ofp_match*) buffer; + m->type = hton16(this->type_); + m->length = hton16(this->length_); + return 0; +} + +of_error MatchHeader::unpack(uint8_t *buffer) { + struct of13::ofp_match *m = (struct of13::ofp_match*) buffer; + this->type_ = ntoh16(m->type); + this->length_ = ntoh16(m->length); + if (this->length_ < sizeof(struct of13::ofp_match)) { + return openflow_error(of13::OFPET_BAD_MATCH, of13::OFPBMC_BAD_LEN); + } + return 0; +} + +OXMTLV::OXMTLV() + : class__(0), + field_(0), + has_mask_(0), + length_(0) { +} + +OXMTLV::OXMTLV(uint16_t class_, uint8_t field, bool has_mask, uint8_t length) + : class__(class_), + field_(field), + has_mask_(has_mask), + length_(has_mask?length<<1:length) { +} + +bool OXMTLV::equals(const OXMTLV &other) { + return ((this->class__ == other.class__) && (this->field_ == other.field_) + && (this->has_mask_ == other.has_mask_) + && (this->length_ == other.length_)); +} + +bool OXMTLV::operator==(const OXMTLV &other) const { + return ((this->class__ == other.class__) && (this->field_ == other.field_) + && (this->has_mask_ && other.has_mask_) + && (this->length_ == other.length_)); +} + +bool OXMTLV::operator!=(const OXMTLV &other) const { + return !(*this == other); +} + +OXMTLV& OXMTLV::operator=(const OXMTLV& field) { + this->class__ = field.class__; + this->field_ = field.field_; + this->has_mask_ = field.has_mask_; + this->length_ = field.length_; + return *this; +} + +void OXMTLV::create_oxm_req(uint16_t eth_type1, uint16_t eth_type2, + uint8_t ip_proto, uint8_t icmp) { + this->reqs.eth_type_req[0] = eth_type1; + this->reqs.eth_type_req[1] = eth_type2; + this->reqs.ip_proto_req = ip_proto; + this->reqs.icmp_req = icmp; +} + +size_t OXMTLV::pack(uint8_t *buffer) { + uint32_t header = hton32( + OXMTLV::make_header(this->class__, this->field_, this->has_mask_, + this->length_)); + memcpy(buffer, &header, sizeof(uint32_t)); + return 0; +} + +of_error OXMTLV::unpack(uint8_t *buffer) { + uint32_t header = ntoh32(*((uint32_t*) buffer)); + this->class__ = oxm_class(header); + this->field_ = oxm_field(header); + this->has_mask_ = oxm_has_mask(header); + this->length_ = oxm_length(header); + return 0; +} + +uint32_t OXMTLV::make_header(uint16_t class_, uint8_t field, bool has_mask, + uint8_t length) { + return (((class_) << 16) | ((field) << 9) | ((has_mask ? 1 : 0) << 8) + | (length)); + +} + +uint16_t OXMTLV::oxm_class(uint32_t header) { + return ((header) >> 16); +} + +uint8_t OXMTLV::oxm_field(uint32_t header) { + return (((header) >> 9) & 0x7f); +} + +bool OXMTLV::oxm_has_mask(uint32_t header) { + return (((header) >> 8) & 1); + +} + +uint8_t OXMTLV::oxm_length(uint32_t header) { + return ((header) & 0xff); +} + +InPort::InPort() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PORT, false, + of13::OFP_OXM_IN_PORT_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +InPort::InPort(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PORT, false, + of13::OFP_OXM_IN_PORT_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool InPort::equals(const OXMTLV &other) { + if (const InPort * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& InPort::operator=(const OXMTLV& field) { + const InPort& port = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = port.value_; + return *this; +} +; + +size_t InPort::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error InPort::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +InPhyPort::InPhyPort() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PHY_PORT, false, + of13::OFP_OXM_IN_PHY_PORT_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +InPhyPort::InPhyPort(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PHY_PORT, false, + of13::OFP_OXM_IN_PHY_PORT_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool InPhyPort::equals(const OXMTLV &other) { + + if (const InPhyPort * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& InPhyPort::operator=(const OXMTLV& field) { + const InPhyPort& phy_port = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = phy_port.value_; + return *this; +} +; + +size_t InPhyPort::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error InPhyPort::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +Metadata::Metadata() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, false, + of13::OFP_OXM_METADATA_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +Metadata::Metadata(uint64_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, false, + of13::OFP_OXM_METADATA_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +Metadata::Metadata(uint64_t value, uint64_t mask) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, true, + of13::OFP_OXM_METADATA_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool Metadata::equals(const OXMTLV &other) { + + if (const Metadata * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& Metadata::operator=(const OXMTLV& field) { + const Metadata& meta = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = meta.value_; + this->mask_ = meta.mask_; + return *this; +} +; + +size_t Metadata::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint64_t mask = hton64(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint64_t value = hton64(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error Metadata::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh64(*((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh64( + *((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN + len))); + } + return 0; +} + +EthDst::EthDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthDst::EthDst(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +EthDst::EthDst(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool EthDst::equals(const OXMTLV &other) { + + if (const EthDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& EthDst::operator=(const OXMTLV& field) { + const EthDst& dst = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dst.value_; + this->mask_ = dst.mask_; + return *this; +} +; + +size_t EthDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error EthDst::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +EthSrc::EthSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthSrc::EthSrc(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +EthSrc::EthSrc(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool EthSrc::equals(const OXMTLV &other) { + + if (const EthSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& EthSrc::operator=(const OXMTLV& field) { + const EthSrc& src = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = src.value_; + this->mask_ = src.mask_; + return *this; +} +; + +size_t EthSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error EthSrc::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +EthType::EthType() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_TYPE, false, + of13::OFP_OXM_ETH_TYPE_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthType::EthType(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_TYPE, false, + of13::OFP_OXM_ETH_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool EthType::equals(const OXMTLV &other) { + + if (const EthType * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& EthType::operator=(const OXMTLV& field) { + const EthType& type = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = type.value_; + return *this; +} +; + +size_t EthType::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error EthType::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +VLANVid::VLANVid() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, false, + of13::OFP_OXM_VLAN_VID_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +VLANVid::VLANVid(uint16_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, false, + of13::OFP_OXM_VLAN_VID_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +VLANVid::VLANVid(uint16_t value, uint16_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, true, + of13::OFP_OXM_VLAN_VID_LEN) { + this->mask_ = mask; + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool VLANVid::equals(const OXMTLV &other) { + + if (const VLANVid * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& VLANVid::operator=(const OXMTLV& field) { + const VLANVid& id = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = id.value_; + this->mask_ = id.mask_; + return *this; +} +; + +size_t VLANVid::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint16_t mask = hton16(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error VLANVid::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh16( + *((uint16_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +VLANPcp::VLANPcp() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_PCP, false, + of13::OFP_OXM_VLAN_PCP_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +VLANPcp::VLANPcp(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_PCP, false, + of13::OFP_OXM_VLAN_PCP_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool VLANPcp::equals(const OXMTLV &other) { + + if (const VLANPcp * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& VLANPcp::operator=(const OXMTLV& field) { + const VLANPcp& pcp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = pcp.value_; + return *this; +} +; + +size_t VLANPcp::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error VLANPcp::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPDSCP::IPDSCP() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_DSCP, false, + of13::OFP_OXM_IP_DSCP_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPDSCP::IPDSCP(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_DSCP, false, + of13::OFP_OXM_IP_DSCP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPDSCP::equals(const OXMTLV &other) { + + if (const IPDSCP * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPDSCP::operator=(const OXMTLV& field) { + const IPDSCP& dscp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dscp.value_; + return *this; +} +; + +size_t IPDSCP::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPDSCP::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPECN::IPECN() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_ECN, false, + of13::OFP_OXM_IP_DSCP_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPECN::IPECN(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_ECN, false, + of13::OFP_OXM_IP_DSCP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPECN::equals(const OXMTLV &other) { + + if (const IPECN * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPECN::operator=(const OXMTLV& field) { + const IPECN& ecn = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ecn.value_; + return *this; +} +; + +size_t IPECN::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPECN::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPProto::IPProto() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_PROTO, false, + of13::OFP_OXM_IP_PROTO_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPProto::IPProto(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_PROTO, false, + of13::OFP_OXM_IP_PROTO_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPProto::equals(const OXMTLV &other) { + + if (const IPProto * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPProto::operator=(const OXMTLV& field) { + const IPProto& proto = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = proto.value_; + return *this; +} +; + +size_t IPProto::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPProto::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *(buffer + of13::OFP_OXM_HEADER_LEN); + return 0; +} + +IPv4Src::IPv4Src() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, false, + of13::OFP_OXM_IPV4_LEN), + value_((uint32_t) 0), + mask_((uint32_t) 0) { + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Src::IPv4Src(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, false, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_((uint32_t) 0) { + // this->value_ = value; + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Src::IPv4Src(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, true, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_(mask) { + // this->value_ = value; + // this->mask_ = mask; + create_oxm_req(0x0800, 0, 0, 0); +} + +bool IPv4Src::equals(const OXMTLV &other) { + + if (const IPv4Src * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv4Src::operator=(const OXMTLV& field) { + const IPv4Src& src = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = src.value_; + this->mask_ = src.mask_; + return *this; +} +; + +size_t IPv4Src::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error IPv4Src::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +IPv4Dst::IPv4Dst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, false, + of13::OFP_OXM_IPV4_LEN), + value_((uint32_t) 0), + mask_((uint32_t) 0) { + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Dst::IPv4Dst(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, false, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_((uint32_t) 0) { + // this->value_ = value; + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Dst::IPv4Dst(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, true, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_(mask) { + // this->value_ = value; + // this->mask_ = mask; + create_oxm_req(0x0800, 0, 0, 0); +} + +bool IPv4Dst::equals(const OXMTLV &other) { + + if (const IPv4Dst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv4Dst::operator=(const OXMTLV& field) { + const IPv4Dst& dst = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dst.value_; + this->mask_ = dst.mask_; + return *this; +} +; + +size_t IPv4Dst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error IPv4Dst::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +TCPSrc::TCPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +TCPSrc::TCPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +bool TCPSrc::equals(const OXMTLV &other) { + + if (const TCPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& TCPSrc::operator=(const OXMTLV& field) { + const TCPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t TCPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error TCPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +TCPDst::TCPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +TCPDst::TCPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +bool TCPDst::equals(const OXMTLV &other) { + + if (const TCPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& TCPDst::operator=(const OXMTLV& field) { + const TCPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t TCPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error TCPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +UDPSrc::UDPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +UDPSrc::UDPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +bool UDPSrc::equals(const OXMTLV &other) { + + if (const UDPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& UDPSrc::operator=(const OXMTLV& field) { + const UDPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t UDPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error UDPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +UDPDst::UDPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +UDPDst::UDPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +bool UDPDst::equals(const OXMTLV &other) { + + if (const UDPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& UDPDst::operator=(const OXMTLV& field) { + const UDPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t UDPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error UDPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +SCTPSrc::SCTPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +SCTPSrc::SCTPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +bool SCTPSrc::equals(const OXMTLV &other) { + + if (const SCTPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& SCTPSrc::operator=(const OXMTLV& field) { + const SCTPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t SCTPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error SCTPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +SCTPDst::SCTPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +SCTPDst::SCTPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +bool SCTPDst::equals(const OXMTLV &other) { + + if (const SCTPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& SCTPDst::operator=(const OXMTLV& field) { + const SCTPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t SCTPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error SCTPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +ICMPv4Type::ICMPv4Type() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + create_oxm_req(0x0800, 0, 1, 0); +} + +ICMPv4Type::ICMPv4Type(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0, 1, 0); +} + +bool ICMPv4Type::equals(const OXMTLV &other) { + + if (const ICMPv4Type * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv4Type::operator=(const OXMTLV& field) { + const ICMPv4Type& type = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = type.value_; + return *this; +} +; + +size_t ICMPv4Type::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv4Type::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; + +} + +ICMPv4Code::ICMPv4Code() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + create_oxm_req(0x0800, 0, 1, 0); +} + +ICMPv4Code::ICMPv4Code(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0, 1, 0); +} + +bool ICMPv4Code::equals(const OXMTLV &other) { + + if (const ICMPv4Code * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv4Code::operator=(const OXMTLV& field) { + const ICMPv4Code& code = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = code.value_; + return *this; +} +; + +size_t ICMPv4Code::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv4Code::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +ARPOp::ARPOp() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_OP, false, + of13::OFP_OXM_ARP_OP_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPOp::ARPOp(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_OP, false, + of13::OFP_OXM_ARP_OP_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPOp::equals(const OXMTLV &other) { + + if (const ARPOp * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ARPOp::operator=(const OXMTLV& field) { + const ARPOp& op = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = op.value_; + return *this; +} +; + +size_t ARPOp::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error ARPOp::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +ARPSPA::ARPSPA() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, false, + of13::OFP_OXM_IPV4_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSPA::ARPSPA(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, false, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSPA::ARPSPA(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, true, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + this->mask_ = mask; +} + +bool ARPSPA::equals(const OXMTLV &other) { + + if (const ARPSPA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPSPA::operator=(const OXMTLV& field) { + const ARPSPA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPSPA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error ARPSPA::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +ARPTPA::ARPTPA() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, false, + of13::OFP_OXM_IPV4_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTPA::ARPTPA(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, false, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTPA::ARPTPA(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, true, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPTPA::equals(const OXMTLV &other) { + + if (const ARPTPA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPTPA::operator=(const OXMTLV& field) { + const ARPTPA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPTPA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error ARPTPA::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +ARPSHA::ARPSHA() + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, false, + OFP_ETH_ALEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSHA::ARPSHA(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSHA::ARPSHA(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPSHA::equals(const OXMTLV &other) { + + if (const ARPSHA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPSHA::operator=(const OXMTLV& field) { + const ARPSHA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPSHA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error ARPSHA::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +ARPTHA::ARPTHA() + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, false, + OFP_ETH_ALEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTHA::ARPTHA(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTHA::ARPTHA(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPTHA::equals(const OXMTLV &other) { + + if (const ARPTHA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPTHA::operator=(const OXMTLV& field) { + const ARPTHA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPTHA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error ARPTHA::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +IPv6Src::IPv6Src() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, false, + of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Src::IPv6Src(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, false, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Src::IPv6Src(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, true, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Src::equals(const OXMTLV &other) { + + if (const IPv6Src * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Src::operator=(const OXMTLV& field) { + const IPv6Src& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPv6Src::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), this->mask_.getIPv6(), + len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), len); + return 0; +} + +of_error IPv6Src::unpack(uint8_t *buffer) { + // uint8_t *ip = buffer + of13::OFP_OXM_HEADER_LEN; + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + ip += 1; + this->mask_ = IPAddress(*ip); + } + return 0; +} + +IPv6Dst::IPv6Dst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, false, + of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Dst::IPv6Dst(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, false, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Dst::IPv6Dst(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, true, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Dst::equals(const OXMTLV &other) { + + if (const IPv6Dst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Dst::operator=(const OXMTLV& field) { + const IPv6Dst& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPv6Dst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), this->mask_.getIPv6(), + len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), len); + return 0; +} + +of_error IPv6Dst::unpack(uint8_t *buffer) { + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + // uint8_t *ip = buffer + of13::OFP_OXM_HEADER_LEN; + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + if (this->has_mask_) { + ip += 1; + this->mask_ = IPAddress(*ip); + } + return 0; +} + +IPV6Flabel::IPV6Flabel() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, false, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPV6Flabel::IPV6Flabel(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, false, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPV6Flabel::IPV6Flabel(uint32_t value, uint32_t mask) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, true, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPV6Flabel::equals(const OXMTLV &other) { + + if (const IPV6Flabel * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPV6Flabel::operator=(const OXMTLV& field) { + const IPV6Flabel& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPV6Flabel::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t mask = hton32(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error IPV6Flabel::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh32( + *((uint32_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +ICMPv6Type::ICMPv6Type() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + create_oxm_req(0, 0x86dd, 58, 0); +} + +ICMPv6Type::ICMPv6Type(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 0); +} + +bool ICMPv6Type::equals(const OXMTLV &other) { + + if (const ICMPv6Type * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv6Type::operator=(const OXMTLV& field) { + const ICMPv6Type& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t ICMPv6Type::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv6Type::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +ICMPv6Code::ICMPv6Code() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + create_oxm_req(0, 0x86dd, 58, 0); +} + +ICMPv6Code::ICMPv6Code(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 0); +} + +bool ICMPv6Code::equals(const OXMTLV &other) { + + if (const ICMPv6Code * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv6Code::operator=(const OXMTLV& field) { + const ICMPv6Code& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t ICMPv6Code::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv6Code::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPv6NDTarget::IPv6NDTarget() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TARGET, + false, of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 58, 135); +} + +IPv6NDTarget::IPv6NDTarget(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TARGET, + false, of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 135); +} + +bool IPv6NDTarget::equals(const OXMTLV &other) { + + if (const IPv6NDTarget * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDTarget::operator=(const OXMTLV& field) { + const IPv6NDTarget& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDTarget::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), + this->length_); + return 0; +} + +of_error IPv6NDTarget::unpack(uint8_t *buffer) { + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + return 0; +} + +IPv6NDTLL::IPv6NDTLL() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TLL, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0x86dd, 58, 136); +} + +IPv6NDTLL::IPv6NDTLL(EthAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TLL, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 136); +} + +bool IPv6NDTLL::equals(const OXMTLV &other) { + + if (const IPv6NDTLL * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDTLL::operator=(const OXMTLV& field) { + const IPv6NDTLL& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDTLL::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), + this->length_); + return 0; +} + +of_error IPv6NDTLL::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + return 0; +} + +IPv6NDSLL::IPv6NDSLL() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_SLL, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0x86dd, 58, 136); +} + +IPv6NDSLL::IPv6NDSLL(EthAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_SLL, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 136); +} + +bool IPv6NDSLL::equals(const OXMTLV &other) { + + if (const IPv6NDSLL * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDSLL::operator=(const OXMTLV& field) { + const IPv6NDSLL& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDSLL::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), + this->length_); + return 0; +} + +of_error IPv6NDSLL::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + return 0; +} + +MPLSLabel::MPLSLabel() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_LABEL, false, + of13::OFP_OXM_MPLS_LABEL_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSLabel::MPLSLabel(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_LABEL, false, + of13::OFP_OXM_MPLS_LABEL_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSLabel::equals(const OXMTLV &other) { + + if (const MPLSLabel * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSLabel::operator=(const OXMTLV& field) { + const MPLSLabel& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSLabel::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error MPLSLabel::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +MPLSTC::MPLSTC() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_TC, false, + of13::OFP_OXM_MPLS_TC_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSTC::MPLSTC(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_TC, false, + of13::OFP_OXM_MPLS_TC_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSTC::equals(const OXMTLV &other) { + + if (const MPLSTC * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSTC::operator=(const OXMTLV& field) { + const MPLSTC& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSTC::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error MPLSTC::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +MPLSBOS::MPLSBOS() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_BOS, false, + of13::OFP_OXM_MPLS_BOS_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSBOS::MPLSBOS(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_BOS, false, + of13::OFP_OXM_MPLS_BOS_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSBOS::equals(const OXMTLV &other) { + + if (const MPLSBOS * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSBOS::operator=(const OXMTLV& field) { + const MPLSBOS& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSBOS::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error MPLSBOS::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +PBBIsid::PBBIsid() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, false, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + create_oxm_req(0x88E7, 0, 0, 0); +} + +PBBIsid::PBBIsid(uint32_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, false, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + this->value_ = value; + create_oxm_req(0x88E7, 0, 0, 0); +} + +PBBIsid::PBBIsid(uint32_t value, uint32_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, true, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x88E7, 0, 0, 0); +} + +bool PBBIsid::equals(const OXMTLV &other) { + + if (const PBBIsid * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& PBBIsid::operator=(const OXMTLV& field) { + const PBBIsid& pbb = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = pbb.value_; + this->mask_ = pbb.mask_; + return *this; +} +; + +size_t PBBIsid::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t mask = hton32(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error PBBIsid::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh32( + *((uint32_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +TUNNELId::TUNNELId() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TUNNEL_ID, false, + of13::OFP_OXM_TUNNEL_ID_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +TUNNELId::TUNNELId(uint64_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TUNNEL_ID, false, + of13::OFP_OXM_TUNNEL_ID_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +TUNNELId::TUNNELId(uint64_t value, uint64_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFP_OXM_TUNNEL_ID_LEN, true, + of13::OFP_OXM_TUNNEL_ID_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool TUNNELId::equals(const OXMTLV &other) { + + if (const TUNNELId * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& TUNNELId::operator=(const OXMTLV& field) { + const TUNNELId& tunnel = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tunnel.value_; + this->mask_ = tunnel.mask_; + return *this; +} + +size_t TUNNELId::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint64_t mask = hton64(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint64_t value = hton64(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error TUNNELId::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh64( + *((uint64_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +IPv6Exthdr::IPv6Exthdr() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, false, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Exthdr::IPv6Exthdr(uint16_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, false, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Exthdr::IPv6Exthdr(uint16_t value, uint16_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, true, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + this->mask_ = mask; + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Exthdr::equals(const OXMTLV &other) { + + if (const IPv6Exthdr * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Exthdr::operator=(const OXMTLV& field) { + const IPv6Exthdr& hdr = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = hdr.value_; + this->mask_ = hdr.mask_; + return *this; +} +; + +size_t IPv6Exthdr::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint16_t mask = hton16(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error IPv6Exthdr::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh16( + *((uint16_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +Match::Match() { + //: oxm_tlvs_(OXM_NUM) { + this->type_ = of13::OFPMT_OXM; + this->length_ = sizeof(struct of13::ofp_match) - 4; + memset(oxm_tlvs_, 0, sizeof(oxm_tlvs_)); +} + +Match::Match(const Match &match) { + this->type_ = match.type_; + this->length_ = 4; + memset(oxm_tlvs_, 0, sizeof(oxm_tlvs_)); + //this->oxm_tlvs_.reserve(OXM_NUM); + for (std::vector::const_iterator it = match.curr_tlvs_.begin(); + it != match.curr_tlvs_.end(); ++it) { + this->curr_tlvs_.push_back((*it)); + this->oxm_tlvs_[*it] = match.oxm_tlvs_[*it]->clone(); + this->length_ += of13::OFP_OXM_HEADER_LEN + + this->oxm_tlvs_[*it]->length(); + } +} + +Match& Match::operator=(Match other) { + swap(*this, other); + return *this; +} + +void Match::swap(Match& first, Match& second) { + std::swap(first.type_, second.type_); + std::swap(first.length_, second.length_); + std::swap(first.oxm_tlvs_, second.oxm_tlvs_); + std::swap(first.curr_tlvs_, second.curr_tlvs_); +} + +Match::~Match() { + for (std::vector::iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + delete this->oxm_tlvs_[*it]; + } +} + +OXMTLV * Match::make_oxm_tlv(uint8_t field) { + switch (field) { + case (of13::OFPXMT_OFB_IN_PORT): { + return new InPort(); + } + case (of13::OFPXMT_OFB_IN_PHY_PORT): { + return new InPhyPort(); + } + case (of13::OFPXMT_OFB_METADATA): { + return new Metadata(); + } + case (of13::OFPXMT_OFB_ETH_SRC): { + return new EthSrc(); + } + case (of13::OFPXMT_OFB_ETH_DST): { + return new EthDst(); + } + case (of13::OFPXMT_OFB_ETH_TYPE): { + return new EthType(); + } + case (of13::OFPXMT_OFB_VLAN_VID): { + return new VLANVid(); + } + case (of13::OFPXMT_OFB_VLAN_PCP): { + return new VLANPcp(); + } + case (of13::OFPXMT_OFB_IP_DSCP): { + return new IPDSCP(); + } + case (of13::OFPXMT_OFB_IP_ECN): { + return new IPECN(); + } + case (of13::OFPXMT_OFB_IP_PROTO): { + return new IPProto(); + } + case (of13::OFPXMT_OFB_IPV4_SRC): { + return new IPv4Src(); + } + case (of13::OFPXMT_OFB_IPV4_DST): { + return new IPv4Dst(); + } + case (of13::OFPXMT_OFB_TCP_SRC): { + return new TCPSrc(); + } + case (of13::OFPXMT_OFB_TCP_DST): { + return new TCPDst(); + } + case (of13::OFPXMT_OFB_UDP_SRC): { + return new UDPSrc(); + } + case (of13::OFPXMT_OFB_UDP_DST): { + return new UDPDst(); + } + case (of13::OFPXMT_OFB_SCTP_SRC): { + return new SCTPSrc(); + } + case (of13::OFPXMT_OFB_SCTP_DST): { + return new SCTPDst(); + } + case (of13::OFPXMT_OFB_ICMPV4_TYPE): { + return new ICMPv4Type(); + } + case (of13::OFPXMT_OFB_ICMPV4_CODE): { + return new ICMPv4Code(); + } + case (of13::OFPXMT_OFB_ARP_OP): { + return new ARPOp(); + } + case (of13::OFPXMT_OFB_ARP_SPA): { + return new ARPSPA(); + } + case (of13::OFPXMT_OFB_ARP_TPA): { + return new ARPTPA(); + } + case (of13::OFPXMT_OFB_ARP_SHA): { + return new ARPSHA(); + } + case (of13::OFPXMT_OFB_ARP_THA): { + return new ARPTHA(); + } + case (of13::OFPXMT_OFB_IPV6_SRC): { + return new IPv6Src(); + } + case (of13::OFPXMT_OFB_IPV6_DST): { + return new IPv6Dst(); + } + case (of13::OFPXMT_OFB_IPV6_FLABEL): { + return new IPV6Flabel(); + } + case (of13::OFPXMT_OFB_ICMPV6_TYPE): { + return new ICMPv6Type(); + } + case (of13::OFPXMT_OFB_ICMPV6_CODE): { + return new ICMPv6Code(); + } + case (of13::OFPXMT_OFB_IPV6_ND_TARGET): { + return new IPv6NDTarget(); + } + case (of13::OFPXMT_OFB_IPV6_ND_SLL): { + return new IPv6NDSLL(); + } + case (of13::OFPXMT_OFB_IPV6_ND_TLL): { + return new IPv6NDTLL(); + } + case (of13::OFPXMT_OFB_MPLS_LABEL): { + return new MPLSLabel(); + } + case (of13::OFPXMT_OFB_MPLS_TC): { + return new MPLSTC(); + } + case (of13::OFPXMT_OFB_MPLS_BOS): { + return new MPLSBOS(); + } + case (of13::OFPXMT_OFB_PBB_ISID): { + return new PBBIsid(); + } + case (of13::OFPXMT_OFB_TUNNEL_ID): { + return new TUNNELId(); + } + case (of13::OFPXMT_OFB_IPV6_EXTHDR): { + return new IPv6Exthdr(); + } + } + return NULL; +} + +bool Match::operator==(const Match &other) const { + for (std::vector::const_iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + OXMTLV *tlv1 = this->oxm_tlvs_[*it]; + OXMTLV *tlv2 = other.oxm_tlvs_[*it]; + if (tlv2) { + if (!tlv1->equals(*tlv2)) { + return false; + } + } + else { + return false; + } + } + return MatchHeader::operator==(other); +} + +bool Match::operator!=(const Match &other) const { + return !(*this == other); +} + +size_t Match::pack(uint8_t *buffer) { + MatchHeader::pack(buffer); + uint8_t *p = buffer + (sizeof(struct of13::ofp_match) - 4); + std::sort(this->curr_tlvs_.begin(), this->curr_tlvs_.end()); + for (std::vector::iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + this->oxm_tlvs_[*it]->pack(p); + p += of13::OFP_OXM_HEADER_LEN + this->oxm_tlvs_[*it]->length(); + } + return 0; +} + +of_error Match::unpack(uint8_t *buffer) { + MatchHeader::unpack(buffer); + size_t len = this->length_ - (sizeof(struct of13::ofp_match) - 4); + uint8_t * p = buffer + (sizeof(struct of13::ofp_match) - 4); + OXMTLV *oxm_tlv; + while (len) { + uint32_t header = ntoh32(*((uint32_t*) p)); + oxm_tlv = make_oxm_tlv(oxm_tlv->oxm_field(header)); + if (!oxm_tlv) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); + } + oxm_tlv->unpack(p); + if (check_dup(oxm_tlv)) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_DUP_FIELD); + } + if (!check_pre_req(oxm_tlv)) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_PREREQ); + } + this->curr_tlvs_.push_back(oxm_tlv->field()); + this->oxm_tlvs_[oxm_tlv->field()] = oxm_tlv; + len -= of13::OFP_OXM_HEADER_LEN + oxm_tlv->length(); + p += of13::OFP_OXM_HEADER_LEN + oxm_tlv->length(); + } + if (len) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_LEN); + } + return 0; +} + +OXMTLV * Match::oxm_field(uint8_t field) { + return this->oxm_tlvs_[field]; +} + +bool Match::check_pre_req(OXMTLV *tlv) { + /*Check ICMP type*/ + struct oxm_req r = tlv->oxm_reqs(); + if (r.icmp_req) { + ICMPv6Type *icmp_type = icmpv6_type(); + if (icmp_type) { + if (icmp_type->value() != r.icmp_req) { + return false; + } + } + else { + return false; + } + } + if (r.ip_proto_req) { + IPProto *proto = ip_proto(); + if (proto) { + if (proto->value() != r.ip_proto_req) { + return false; + } + } + else { + return false; + } + } + + /* Check for eth_type */ + if (!r.eth_type_req[0]) { + return true; + } + else { + EthType *type = eth_type(); + if (type) { + if (type->value() == r.eth_type_req[0]) { + return true; + } + else if (r.eth_type_req[1] && type->value() == r.eth_type_req[1]) { + return true; + } + } + else { + return false; + } + } + return false; +} + +bool Match::check_dup(OXMTLV *tlv) { + if (this->oxm_tlvs_[tlv->field()]) { + return true; + } + return false; +} + +void Match::add_oxm_field(OXMTLV &tlv) { + if (check_dup(&tlv)) return; + this->curr_tlvs_.push_back(tlv.field()); + this->oxm_tlvs_[tlv.field()] = tlv.clone(); + this->length_ += of13::OFP_OXM_HEADER_LEN + tlv.length(); +} + +void Match::add_oxm_field(OXMTLV* tlv) { + if (check_dup(tlv)) return; + this->curr_tlvs_.push_back(tlv->field()); + this->oxm_tlvs_[tlv->field()] = tlv; + this->length_ += of13::OFP_OXM_HEADER_LEN + tlv->length(); +} + +InPort* Match::in_port() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IN_PORT)); +} + +InPhyPort* Match::in_phy_port() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IN_PHY_PORT)); +} + +Metadata* Match::metadata() { + return static_cast(oxm_field(of13::OFPXMT_OFB_METADATA)); +} + +EthSrc* Match::eth_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_SRC)); +} + +EthDst* Match::eth_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_DST)); +} + +EthType* Match::eth_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_TYPE)); +} + +VLANVid* Match::vlan_vid() { + return static_cast(oxm_field(of13::OFPXMT_OFB_VLAN_VID)); +} + +VLANPcp* Match::vlan_pcp() { + return static_cast(oxm_field(of13::OFPXMT_OFB_VLAN_PCP)); +} + +IPDSCP* Match::ip_dscp() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_DSCP)); +} + +IPECN* Match::ip_ecn() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_ECN)); +} + +IPProto* Match::ip_proto() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_PROTO)); +} + +IPv4Src* Match::ipv4_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV4_SRC)); +} + +IPv4Dst* Match::ipv4_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV4_DST)); +} + +TCPSrc* Match::tcp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TCP_SRC)); +} + +TCPDst* Match::tcp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TCP_DST)); +} + +UDPSrc* Match::udp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_UDP_SRC)); +} + +UDPDst* Match::udp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_UDP_DST)); +} + +SCTPSrc* Match::sctp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_SCTP_SRC)); +} + +SCTPDst* Match::sctp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_SCTP_DST)); +} + +ICMPv4Type* Match::icmpv4_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV4_TYPE)); +} + +ICMPv4Code* Match::icmpv4_code() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV4_CODE)); +} + +ARPOp* Match::arp_op() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_OP)); +} + +ARPSPA* Match::arp_spa() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_SPA)); +} + +ARPTPA* Match::arp_tpa() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_TPA)); +} + +ARPSHA* Match::arp_sha() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_SHA)); +} + +ARPTHA* Match::arp_tha() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_THA)); +} + +IPv6Src* Match::ipv6_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_SRC)); +} + +IPv6Dst* Match::ipv6_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_DST)); +} + +IPV6Flabel* Match::ipv6_flabel() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_FLABEL)); +} + +ICMPv6Type* Match::icmpv6_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV6_TYPE)); +} + +ICMPv6Code* Match::icmpv6_code() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV6_CODE)); +} + +IPv6NDTarget* Match::ipv6_nd_target() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_TARGET)); +} + +IPv6NDSLL* Match::ipv6_nd_sll() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_SLL)); +} + +IPv6NDTLL* Match::ipv6_nd_tll() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_TLL)); +} + +MPLSLabel* Match::mpls_label() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_LABEL)); +} + +MPLSTC* Match::mpls_tc() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_TC)); +} + +MPLSBOS* Match::mpls_bos() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_BOS)); +} + +PBBIsid* Match::pbb_isid() { + return static_cast(oxm_field(of13::OFPXMT_OFB_PBB_ISID)); +} + +TUNNELId* Match::tunnel_id() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TUNNEL_ID)); +} + +IPv6Exthdr* Match::ipv6_exthdr() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_EXTHDR)); +} + +uint16_t Match::oxm_fields_len() { + uint16_t len = 0; + for (std::vector::const_iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + len += of13::OFP_OXM_HEADER_LEN + this->oxm_tlvs_[*it]->length(); + } + return len; +} + +} //End of namespace of13 +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of13/of13meter.cc b/src/ovs/libfluid-msg/of13/of13meter.cc new file mode 100644 index 00000000..0f6d3353 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13meter.cc @@ -0,0 +1,492 @@ +#include "libfluid-msg/util/util.h" +#include "libfluid-msg/of13/of13meter.hh" + +namespace fluid_msg { + +namespace of13 { + +MeterBand::MeterBand() + : type_(0), + rate_(0), + burst_size_(0), + len_(sizeof(struct of13::ofp_meter_band_header)) { + +} + +MeterBand::MeterBand(uint16_t type, uint32_t rate, uint32_t burst_size) + : type_(type), + rate_(rate), + burst_size_(burst_size), + len_(sizeof(struct of13::ofp_meter_band_header)) { +} + +bool MeterBand::equals(const MeterBand &other) { + return ((this->type_ == other.type_) && (this->rate_ == other.rate_) + && (this->burst_size_ == other.burst_size_)); +} + +size_t MeterBand::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_header *bh = + (struct of13::ofp_meter_band_header *) buffer; + bh->type = hton16(this->type_); + bh->len = hton16(this->len_); + bh->rate = hton32(this->rate_); + bh->burst_size = hton32(this->burst_size_); + return this->len_; +} + +of_error MeterBand::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_header *bh = + (struct of13::ofp_meter_band_header *) buffer; + this->type_ = hton16(bh->type); + this->len_ = hton16(bh->len); + this->rate_ = hton32(bh->rate); + this->burst_size_ = hton32(bh->burst_size); + return 0; +} + +MeterBand * MeterBand::make_meter_band(uint16_t type) { + switch (type) { + case (of13::OFPMBT_DROP): { + return new MeterBandDrop(); + } + case (of13::OFPMBT_DSCP_REMARK): { + return new MeterBandDSCPRemark(); + } + case (of13::OFPMBT_EXPERIMENTER): { + return new MeterBandExperimenter(); + } + } + return NULL; +} + +MeterBandList::MeterBandList(std::list band_list) { + this->band_list_ = band_list_; + for (std::list::const_iterator it = band_list.begin(); + it != band_list.end(); ++it) { + this->length_ += (*it)->len(); + } +} + +MeterBandList::MeterBandList(const MeterBandList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = other.band_list_.begin(); + it != other.band_list_.end(); ++it) { + this->band_list_.push_back((*it)->clone()); + } +} + +MeterBandList::~MeterBandList() { + this->band_list_.remove_if(MeterBand::delete_all); +} + +bool MeterBandList::operator==(const MeterBandList &other) const { + std::list::const_iterator ot = other.band_list_.begin(); + for (std::list::const_iterator it = this->band_list_.begin(); + it != this->band_list_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool MeterBandList::operator!=(const MeterBandList &other) const { + return !(*this == other); +} + +size_t MeterBandList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->band_list_.begin(), end = + this->band_list_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->len(); + } + return 0; +} + +of_error MeterBandList::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + MeterBand *band; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + band = MeterBand::make_meter_band(type); + band->unpack(p); + this->band_list_.push_back(band); + len -= band->len(); + p += band->len(); + } + return 0; +} + +MeterBandList& MeterBandList::operator=(MeterBandList other) { + swap(*this, other); + return *this; +} + +void swap(MeterBandList& first, MeterBandList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.band_list_, second.band_list_); +} + +void MeterBandList::add_band(MeterBand *band) { + this->band_list_.push_back(band); + this->length_ += band->len(); +} + +MeterBandDrop::MeterBandDrop() + : MeterBand(of13::OFPMBT_DROP, 0, 0) { + this->len_ = sizeof(struct of13::ofp_meter_band_drop); +} + +MeterBandDrop::MeterBandDrop(uint32_t rate, uint32_t burst_size) + : MeterBand(of13::OFPMBT_DROP, rate, burst_size) { + this->len_ = sizeof(struct of13::ofp_meter_band_drop); +} + +size_t MeterBandDrop::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_drop *bd = + (struct of13::ofp_meter_band_drop*) buffer; + MeterBand::pack(buffer); + memset(bd->pad, 0x0, 4); + return this->len_; +} + +of_error MeterBandDrop::unpack(uint8_t* buffer) { + MeterBand::unpack(buffer); + return 0; +} + +MeterBandDSCPRemark::MeterBandDSCPRemark() + : MeterBand(of13::OFPMBT_DSCP_REMARK, 0, 0), + prec_level_(0) { + this->len_ = sizeof(struct of13::ofp_meter_band_dscp_remark); +} + +MeterBandDSCPRemark::MeterBandDSCPRemark(uint32_t rate, uint32_t burst_size, + uint8_t prec_level) + : MeterBand(of13::OFPMBT_DSCP_REMARK, rate, burst_size) { + this->prec_level_ = prec_level; + this->len_ = sizeof(struct of13::ofp_meter_band_dscp_remark); +} + +bool MeterBandDSCPRemark::equals(const MeterBand &other) { + + if (const MeterBandDSCPRemark * band = + dynamic_cast(&other)) { + return ((MeterBand::equals(other)) + && (this->prec_level_ == band->prec_level_)); + } + else { + return false; + } +} + +size_t MeterBandDSCPRemark::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_dscp_remark *bd = + (struct of13::ofp_meter_band_dscp_remark*) buffer; + MeterBand::pack(buffer); + bd->prec_level = this->prec_level_; + memset(bd->pad, 0x0, 3); + return this->len_; +} + +of_error MeterBandDSCPRemark::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_dscp_remark *bd = + (struct of13::ofp_meter_band_dscp_remark*) buffer; + MeterBand::unpack(buffer); + this->prec_level_ = bd->prec_level; + return 0; +} + +MeterBandExperimenter::MeterBandExperimenter() + : experimenter_(0) { + this->len_ = sizeof(struct of13::ofp_meter_band_experimenter); +} + +MeterBandExperimenter::MeterBandExperimenter(uint32_t rate, uint32_t burst_size, + uint32_t experimenter) + : MeterBand(of13::OFPMBT_EXPERIMENTER, rate, burst_size) { + this->experimenter_ = experimenter; + this->len_ = sizeof(struct of13::ofp_meter_band_experimenter); +} + +bool MeterBandExperimenter::equals(const MeterBand &other) { + + if (const MeterBandExperimenter * band = + dynamic_cast(&other)) { + return ((MeterBand::equals(other)) + && (this->experimenter_ == band->experimenter_)); + } + else { + return false; + } +} + +size_t MeterBandExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_experimenter *be = + (struct of13::ofp_meter_band_experimenter*) buffer; + MeterBand::pack(buffer); + be->experimenter = hton32(this->experimenter_); + return this->len_; +} + +of_error MeterBandExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_experimenter *be = + (struct of13::ofp_meter_band_experimenter*) buffer; + MeterBand::unpack(buffer); + this->experimenter_ = ntoh32(be->experimenter); + return 0; +} + +MeterConfig::MeterConfig() + : flags_(0), + meter_id_(0), + length_(sizeof(struct of13::ofp_meter_config)) { +} + +MeterConfig::MeterConfig(uint16_t flags, uint32_t meter_id) + : flags_(flags), + meter_id_(meter_id), + length_(sizeof(struct of13::ofp_meter_config)) { +} + +MeterConfig::MeterConfig(uint16_t flags, uint32_t meter_id, MeterBandList bands) + : bands_(bands) { + this->flags_ = flags; + this->meter_id_ = meter_id; + this->length_ = sizeof(struct of13::ofp_meter_config) + bands.length(); +} + +bool MeterConfig::operator==(const MeterConfig &other) const { + return ((this->flags_ == other.flags_) + && (this->meter_id_ == other.meter_id_) + && (this->bands_ == other.bands_)); +} + +bool MeterConfig::operator!=(const MeterConfig &other) const { + return !(*this == other); +} + +size_t MeterConfig::pack(uint8_t* buffer) { + struct of13::ofp_meter_config *mc = (struct of13::ofp_meter_config*) buffer; + mc->length = hton16(this->length_); + mc->flags = hton16(this->flags_); + mc->meter_id = hton32(this->meter_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_config); + this->bands_.pack(p); + return this->length_; +} + +of_error MeterConfig::unpack(uint8_t* buffer) { + struct of13::ofp_meter_config *mc = (struct of13::ofp_meter_config *) buffer; + this->length_ = ntoh16(mc->length); + this->flags_ = ntoh16(mc->flags); + this->meter_id_ = ntoh32(mc->meter_id); + this->bands_.length(this->length_ - sizeof(struct of13::ofp_meter_config)); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_config); + this->bands_.unpack(p); + return 0; +} + +void MeterConfig::bands(MeterBandList bands) { + this->bands_ = bands; + this->length_ += bands.length(); +} + +void MeterConfig::add_band(MeterBand* band) { + this->bands_.add_band(band); + this->length_ += band->len(); +} + +MeterFeatures::MeterFeatures() + : max_meter_(0), + band_types_(0), + capabilities_(0), + max_bands_(0), + max_color_(0) { + +} + +MeterFeatures::MeterFeatures(uint32_t max_meter, uint32_t band_types, + uint32_t capabilities, uint8_t max_bands, uint8_t max_color) + : max_meter_(max_meter), + band_types_(band_types), + capabilities_(capabilities), + max_bands_(max_bands), + max_color_(max_color) { +} + +bool MeterFeatures::operator==(const MeterFeatures &other) const { + return ((this->max_meter_ == other.max_meter_) + && (this->band_types_ == other.band_types_) + && (this->capabilities_ == other.capabilities_) + && (this->max_bands_ == other.max_bands_) + && (this->max_color_ == other.max_color_)); +} + +bool MeterFeatures::operator!=(const MeterFeatures &other) const { + return !(*this == other); +} + +size_t MeterFeatures::pack(uint8_t* buffer) { + struct of13::ofp_meter_features *mf = + (struct of13::ofp_meter_features *) buffer; + mf->max_meter = hton32(this->max_meter_); + mf->band_types = hton32(this->band_types_); + mf->capabilities = hton32(this->capabilities_); + mf->max_bands = this->max_bands_; + mf->max_color = this->max_color_; + memset(mf->pad, 0x0, 2); + return 0; +} + +of_error MeterFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_meter_features *mf = + (struct of13::ofp_meter_features *) buffer; + this->max_meter_ = ntoh32(mf->max_meter); + this->band_types_ = ntoh32(mf->band_types); + this->capabilities_ = ntoh32(mf->capabilities); + this->max_bands_ = mf->max_bands; + this->max_color_ = mf->max_color; + return 0; +} + +BandStats::BandStats() + : packet_band_count_(0), + byte_band_count_(0) { +} + +BandStats::BandStats(uint64_t packet_band_count, uint64_t byte_band_count) { + this->packet_band_count_ = packet_band_count; + this->byte_band_count_ = byte_band_count; +} + +bool BandStats::operator==(const BandStats &other) const { + return ((this->packet_band_count_ == other.packet_band_count_) + && (this->byte_band_count_ == other.byte_band_count_)); +} + +bool BandStats::operator!=(const BandStats &other) const { + return !(*this == other); +} + +size_t BandStats::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_stats *mb = + (struct of13::ofp_meter_band_stats *) buffer; + mb->packet_band_count = hton64(this->packet_band_count_); + mb->byte_band_count = hton64(this->byte_band_count_); + return 0; +} + +of_error BandStats::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_stats *mb = + (struct of13::ofp_meter_band_stats *) buffer; + this->packet_band_count_ = ntoh64(mb->packet_band_count); + this->byte_band_count_ = ntoh64(mb->byte_band_count); + return 0; +} + +MeterStats::MeterStats() + : meter_id_(0), + flow_count_(0), + packet_in_count_(0), + byte_in_count_(0), + duration_sec_(0), + duration_nsec_(0), + len_(sizeof(struct of13::ofp_meter_stats)) { + +} + +MeterStats::MeterStats(uint32_t meter_id, uint32_t flow_count, + uint64_t packet_in_count, uint64_t byte_in_count, uint32_t duration_sec, + uint32_t duration_nsec) + : meter_id_(meter_id), + flow_count_(flow_count), + packet_in_count_(packet_in_count), + byte_in_count_(byte_in_count), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + len_(sizeof(struct of13::ofp_meter_stats)) { +} + +MeterStats::MeterStats(uint32_t meter_id, uint32_t flow_count, + uint64_t packet_in_count, uint64_t byte_in_count, uint32_t duration_sec, + uint32_t duration_nsec, std::vector band_stats) { + this->meter_id_ = meter_id; + this->flow_count_ = flow_count; + this->packet_in_count_ = packet_in_count; + this->byte_in_count_ = byte_in_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->len_ = sizeof(struct of13::ofp_meter_stats) + + band_stats.size() * sizeof(struct of13::ofp_meter_band_stats); +} + +bool MeterStats::operator==(const MeterStats &other) const { + return ((this->meter_id_ == other.meter_id_) + && (this->flow_count_ == other.flow_count_) + && (this->packet_in_count_ == other.packet_in_count_) + && (this->byte_in_count_ == other.byte_in_count_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} + +bool MeterStats::operator!=(const MeterStats &other) const { + return !(*this == other); +} + +size_t MeterStats::pack(uint8_t* buffer) { + struct of13::ofp_meter_stats *ms = (struct of13::ofp_meter_stats*) buffer; + ms->meter_id = hton32(this->meter_id_); + ms->len = hton16(this->len_); + ms->flow_count = hton32(this->flow_count_); + ms->packet_in_count = hton64(this->packet_in_count_); + ms->byte_in_count = hton64(this->byte_in_count_); + ms->duration_sec = hton32(this->duration_sec_); + ms->duration_nsec = hton32(this->duration_nsec_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_stats); + for (std::vector::iterator it = this->band_stats_.begin(); + it != this->band_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_meter_band_stats); + } + return 0; +} + +of_error MeterStats::unpack(uint8_t* buffer) { + struct of13::ofp_meter_stats *ms = (struct of13::ofp_meter_stats*) buffer; + this->meter_id_ = ntoh32(ms->meter_id); + this->len_ = ntoh16(ms->len); + this->flow_count_ = hton32(ms->flow_count); + this->packet_in_count_ = ntoh64(ms->packet_in_count); + this->byte_in_count_ = ntoh64(ms->byte_in_count); + this->duration_sec_ = ntoh32(ms->duration_sec); + this->duration_nsec_ = ntoh32(ms->duration_nsec); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_stats); + size_t len = this->len_ - sizeof(struct of13::ofp_meter_stats); + while (len) { + BandStats stats; + stats.unpack(p); + this->band_stats_.push_back(stats); + p += sizeof(struct of13::ofp_meter_band_stats); + len -= sizeof(struct of13::ofp_meter_band_stats); + } + return 0; +} + +void MeterStats::band_stats(std::vector band_stats) { + this->band_stats_ = band_stats; + this->len_ += band_stats.size() * sizeof(struct of13::ofp_meter_band_stats); +} + +void MeterStats::add_band_stats(BandStats stats) { + this->band_stats_.push_back(stats); + this->len_ += sizeof(struct of13::ofp_meter_band_stats); +} + +} //End of namespace fluid_msg + +} diff --git a/src/ovs/libfluid-msg/of13msg.cc b/src/ovs/libfluid-msg/of13msg.cc new file mode 100644 index 00000000..83cd61ae --- /dev/null +++ b/src/ovs/libfluid-msg/of13msg.cc @@ -0,0 +1,2940 @@ +#include "libfluid-msg/of13msg.hh" + +namespace fluid_msg { + +RoleCommon::RoleCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + role_(0), + generation_id_(0) { +} + +RoleCommon::RoleCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t role, uint64_t generation_id) + : OFMsg(version, type, xid), + role_(role), + generation_id_(generation_id) { + this->length_ = sizeof(struct ofp_role_request); +} + +bool RoleCommon::operator==(const RoleCommon &other) const { + return ((OFMsg::operator==(other)) && (this->role_ == other.role_) + && (this->generation_id_ == other.generation_id_) + && (this->length_ == other.length_)); +} + +bool RoleCommon::operator!=(const RoleCommon &other) const { + return !(*this == other); +} + +uint8_t* RoleCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_role_request * rq = (struct ofp_role_request*) buffer; + rq->role = hton32(this->role_); + memset(rq->pad, 0x0, 4); + rq->generation_id = hton64(this->generation_id_); + return buffer; +} + +of_error RoleCommon::unpack(uint8_t *buffer) { + struct ofp_role_request * rq = (struct ofp_role_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_role_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->role_ = ntoh32(rq->role); + memset(rq->pad, 0x0, 4); + this->generation_id_ = ntoh64(rq->generation_id); + return 0; +} + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + packet_in_mask_(2, 0), + port_status_mask_(2, 0), + flow_removed_mask_(2, 0) { +} + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type, + uint32_t xid) + : OFMsg(version, type, xid), + packet_in_mask_(2, 0), + port_status_mask_(2, 0), + flow_removed_mask_(2, 0) { + this->length_ = sizeof(struct ofp_async_config); +} +; + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type, + uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : OFMsg(version, type, xid), + packet_in_mask_(packet_in_mask), + port_status_mask_(port_status_mask), + flow_removed_mask_(flow_removed_mask) { + this->length_ = sizeof(struct ofp_async_config); +} + +bool AsyncConfigCommon::operator==(const AsyncConfigCommon &other) const { + return ((OFMsg::operator==(other)) + && (this->packet_in_mask_ == other.packet_in_mask_) + && (this->port_status_mask_ == other.port_status_mask_) + && (this->flow_removed_mask_ == other.flow_removed_mask_)); +} + +bool AsyncConfigCommon::operator!=(const AsyncConfigCommon &other) const { + return !(*this == other); +} + +uint8_t* AsyncConfigCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_async_config *ar = (struct ofp_async_config *) buffer; + ar->packet_in_mask[0] = hton32(this->packet_in_mask_[0]); + ar->packet_in_mask[1] = hton32(this->packet_in_mask_[1]); + ar->port_status_mask[0] = hton32(this->port_status_mask_[0]); + ar->port_status_mask[1] = hton32(this->port_status_mask_[1]); + ar->flow_removed_mask[0] = hton32(this->flow_removed_mask_[0]); + ar->flow_removed_mask[1] = hton32(this->flow_removed_mask_[1]); + return buffer; +} + +of_error AsyncConfigCommon::unpack(uint8_t *buffer) { + struct ofp_async_config *ar = (struct ofp_async_config *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_async_config)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->packet_in_mask_[0] = ntoh32(ar->packet_in_mask[0]); + this->packet_in_mask_[1] = ntoh32(ar->packet_in_mask[1]); + this->port_status_mask_[0] = ntoh32(ar->port_status_mask[0]); + this->port_status_mask_[1] = ntoh32(ar->port_status_mask[1]); + this->flow_removed_mask_[0] = ntoh32(ar->flow_removed_mask[0]); + this->flow_removed_mask_[1] = ntoh32(ar->flow_removed_mask[1]); + return 0; +} + +namespace of13 { + +Hello::Hello() + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO) { +} + +Hello::Hello(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO, xid) { +} + +Hello::Hello(uint32_t xid, std::list elements) + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO, xid), + elements_(elements) { + this->length_ += elements_len(); +} + +bool Hello::operator==(const Hello &other) const { + return ((OFMsg::operator==(other)) && (this->elements_ == other.elements_)); +} + +bool Hello::operator!=(const Hello &other) const { + return !(*this == other); +} + +uint8_t* Hello::pack() { + uint8_t* buffer = OFMsg::pack(); + uint8_t *p = buffer + sizeof(struct ofp_fluid_header); + for (std::list::iterator it = + this->elements_.begin(), end = this->elements_.end(); it != end; ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error Hello::unpack(uint8_t* buffer) { + OFMsg::unpack(buffer); + /*Unpack the Hello elements*/ + uint32_t len = this->length_ - sizeof(struct ofp_fluid_header); + uint8_t *p = buffer + sizeof(struct ofp_fluid_header); + while (len) { + HelloElemVersionBitmap he; + he.unpack(p); + len -= he.length(); + this->elements_.push_back(he); + p += he.length(); + } + return 0; +} + +void Hello::elements(std::list elements) { + this->elements_ = elements; + this->length_ += elements_len(); +} + +void Hello::add_element(HelloElemVersionBitmap element) { + this->elements_.push_back(element); + this->length_ += element.length(); + +} + +uint32_t Hello::elements_len() { + uint32_t len = 0; + for (std::list::iterator it = + this->elements_.begin(), end = this->elements_.end(); it != end; ++it) { + len += (*it).length(); + } + return len; +} + +Error::Error() + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code) + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR, xid, err_type, code) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len) + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR, xid, err_type, code, + data, data_len) { +} + +EchoRequest::EchoRequest() + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REQUEST) { +} + +EchoRequest::EchoRequest(uint32_t xid) + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REQUEST, xid) { +} + +EchoReply::EchoReply() + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REPLY) { +} + +EchoReply::EchoReply(uint32_t xid) + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REPLY, xid) { +} + +Experimenter::Experimenter() + : OFMsg(of13::OFP_VERSION, of13::OFPT_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_header); +} + +Experimenter::Experimenter(uint32_t xid, uint32_t experimenter, + uint32_t exp_type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_EXPERIMENTER, xid), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_header); +} + +bool Experimenter::operator==(const Experimenter &other) const { + return ((Experimenter::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool Experimenter::operator!=(const Experimenter &other) const { + return !(*this == other); +} + +uint8_t* Experimenter::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_experimenter_header *em = + (struct of13::ofp_experimenter_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error Experimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_header *em = + (struct of13::ofp_experimenter_header*) buffer; + OFMsg::unpack(buffer); + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +FeaturesRequest::FeaturesRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_FEATURES_REQUEST) { +} + +FeaturesRequest::FeaturesRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_FEATURES_REQUEST, xid) { +} + +uint8_t* FeaturesRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + return buffer; +} + +of_error FeaturesRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +FeaturesReply::FeaturesReply() + : FeaturesReplyCommon(of13::OFP_VERSION, of13::OFPT_FEATURES_REPLY) { + this->length_ = sizeof(struct of13::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint8_t auxiliary_id, + uint32_t capabilities) + : FeaturesReplyCommon(of13::OFP_VERSION, of13::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities), + auxiliary_id_(auxiliary_id) { + this->length_ = sizeof(struct of13::ofp_switch_features); +} + +bool FeaturesReply::operator==(const FeaturesReply &other) const { + return ((FeaturesReplyCommon::operator==(other)) + && (this->auxiliary_id_ == other.auxiliary_id_)); +} + +bool FeaturesReply::operator!=(const FeaturesReply &other) const { + return !(*this == other); +} + +uint8_t* FeaturesReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_switch_features *fr = + (struct of13::ofp_switch_features *) buffer; + fr->datapath_id = hton64(this->datapath_id_); + fr->n_buffers = hton32(this->n_buffers_); + fr->n_tables = this->n_tables_; + memset(fr->pad, 0x0, 2); + fr->auxiliary_id = this->auxiliary_id_; + fr->capabilities = hton32(this->capabilities_); + fr->reserved = 0; + return buffer; +} + +of_error FeaturesReply::unpack(uint8_t *buffer) { + struct of13::ofp_switch_features *fr = + (struct of13::ofp_switch_features *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_switch_features)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->datapath_id_ = ntoh64(fr->datapath_id); + this->n_buffers_ = ntoh32(fr->n_buffers); + this->n_tables_ = fr->n_tables; + memset(fr->pad, 0x0, 2); + this->auxiliary_id_ = fr->auxiliary_id; + this->capabilities_ = ntoh32(fr->capabilities); + return 0; +} + +GetConfigRequest::GetConfigRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REQUEST) { +} + +GetConfigRequest::GetConfigRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REQUEST, xid) { +} + +uint8_t* GetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + return buffer; +} + +of_error GetConfigRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +GetConfigReply::GetConfigReply() + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REPLY) { +} + +GetConfigReply::GetConfigReply(uint32_t xid, uint16_t flags, + uint16_t miss_send_len) + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REPLY, xid, + flags, miss_send_len) { +} + +SetConfig::SetConfig() + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_CONFIG) { +} + +SetConfig::SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_CONFIG, xid, flags, + miss_send_len) { +} + +PacketOut::PacketOut() + : PacketOutCommon(of13::OFP_VERSION, of13::OFPT_PACKET_OUT), + in_port_(0) { + this->length_ = sizeof(struct of13::ofp_packet_out); +} + +PacketOut::PacketOut(uint32_t xid, uint32_t buffer_id, uint32_t in_port) + : PacketOutCommon(of13::OFP_VERSION, of13::OFPT_PACKET_OUT, xid, buffer_id), + in_port_(in_port) { + this->length_ = sizeof(struct of13::ofp_packet_out); +} + +bool PacketOut::operator==(const PacketOut &other) const { + return ((PacketOutCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketOut::operator!=(const PacketOut &other) const { + return !(*this == other); +} + +uint8_t* PacketOut::pack() { + size_t data_size; + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_packet_out *po = (struct of13::ofp_packet_out*) buffer; + po->buffer_id = hton32(this->buffer_id_); + po->in_port = hton32(this->in_port_); + po->actions_len = hton16(this->actions_len_); + memset(po->pad, 0x0, 6); + this->actions_.pack(buffer + sizeof(struct of13::ofp_packet_out)); + data_size = this->length_ + - (sizeof(struct of13::ofp_packet_out) + this->actions_len_); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_out) + + this->actions_len_; + memcpy(p, this->data_, data_size); + return buffer; +} + +of_error PacketOut::unpack(uint8_t *buffer) { + struct of13::ofp_packet_out *po = (struct of13::ofp_packet_out*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_packet_out)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->buffer_id_ = ntoh32(po->buffer_id); + this->in_port_ = ntoh32(po->in_port); + this->actions_len_ = ntoh16(po->actions_len); + size_t len = this->actions_len_; + uint8_t * p = buffer + sizeof(struct of13::ofp_packet_out); + this->actions_.unpack13(p); + len = this->length_ + - (sizeof(struct of13::ofp_packet_out) + this->actions_len_); + /*Reuse p to calculate the packet data position */ + p = buffer + sizeof(struct of13::ofp_packet_out) + this->actions_len_; + if (len) { + this->data_ = new uint8_t[len]; + memcpy(this->data_, p, len); + } + return 0; +} + +PacketIn::PacketIn() + : PacketInCommon(of13::OFP_VERSION, of13::OFPT_PACKET_IN), + table_id_(0), + cookie_(0) { +} + +PacketIn::PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t total_len, + uint8_t reason, uint8_t table_id, uint64_t cookie) + : PacketInCommon(of13::OFP_VERSION, of13::OFPT_PACKET_IN, xid, buffer_id, + total_len, reason), + table_id_(table_id), + cookie_(cookie) { +} + +uint16_t PacketIn::length() { + return sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + this->data_len_; +} + +bool PacketIn::operator==(const PacketIn &other) const { + return ((PacketInCommon::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->cookie_ == other.cookie_) && (this->match_ == other.match_)); +} + +bool PacketIn::operator!=(const PacketIn &other) const { + return !(*this == other); +} + +uint8_t* PacketIn::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_packet_in) - 4 + this->match_.length(), 8) + - (sizeof(struct of13::ofp_packet_in) - 4 + this->match_.length()); + struct of13::ofp_packet_in *pi = (struct of13::ofp_packet_in*) buffer; + pi->buffer_id = hton32(this->buffer_id_); + pi->total_len = hton16(this->total_len_); + pi->reason = this->reason_; + pi->table_id = this->table_id_; + pi->cookie = hton64(this->cookie_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += match_.length(); + memset(p, 0x0, padding); + p += padding; + memset(p, 0x0, 2); + memcpy(p + 2, this->data_, this->data_len_); + return buffer; +} + +of_error PacketIn::unpack(uint8_t *buffer) { + struct of13::ofp_packet_in *pi = (struct of13::ofp_packet_in*) buffer; + OFMsg::unpack(buffer); + this->buffer_id_ = ntoh32(pi->buffer_id); + this->total_len_ = ntoh16(pi->total_len); + this->reason_ = pi->reason; + this->table_id_ = pi->table_id; + this->cookie_ = ntoh64(pi->cookie); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + p += ROUND_UP(this->match_.length(), 8); + this->data_len_ = this->length_ + - (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + 2); + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, p + 2, this->data_len_); + return 0; +} + +OXMTLV * PacketIn::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void PacketIn::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void PacketIn::add_oxm_field(OXMTLV *field) { + this->match_.add_oxm_field(field); +} + +FlowMod::FlowMod() + : FlowModCommon(of13::OFP_VERSION, of13::OFPT_FLOW_MOD), + instructions_(), + command_(0), + cookie_mask_(0), + table_id_(0), + out_port_(0), + out_group_(0) { +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint64_t cookie_mask, + uint8_t table_id, uint8_t command, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint32_t out_port, uint32_t out_group, uint16_t flags) + : FlowModCommon(of13::OFP_VERSION, of13::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + instructions_(), + command_(command), + cookie_mask_(cookie_mask), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group) { + ; +} + +uint16_t FlowMod::length() { + return sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + this->instructions_.length(); +} + +bool FlowMod::operator==(const FlowMod &other) const { + return ((FlowModCommon::operator==(other)) + && (this->command_ == other.command_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->instructions_ == other.instructions_)); +} + +bool FlowMod::operator!=(const FlowMod &other) const { + return !(*this == other); +} + +uint8_t* FlowMod::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP(this->match_.length(), 8) - this->match_.length(); + struct of13::ofp_flow_mod *fm = (struct of13::ofp_flow_mod*) buffer; + fm->cookie = hton64(this->cookie_); + fm->cookie_mask = hton64(this->cookie_mask_); + fm->table_id = this->table_id_; + fm->command = this->command_; + fm->idle_timeout = hton16(this->idle_timeout_); + fm->hard_timeout = hton16(this->hard_timeout_); + fm->priority = hton16(this->priority_); + fm->buffer_id = hton32(this->buffer_id_); + fm->out_port = hton32(this->out_port_); + fm->out_group = hton32(this->out_group_); + fm->flags = hton16(this->flags_); + memset(fm->pad, 0x0, 2); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + p += padding; + this->instructions_.pack(p); + return buffer; +} + +of_error FlowMod::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + of_error err; + struct of13::ofp_flow_mod *fm = (struct of13::ofp_flow_mod*) buffer; + if (this->length_ < sizeof(struct of13::ofp_flow_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->cookie_ = ntoh64(fm->cookie); + this->cookie_mask_ = ntoh64(fm->cookie_mask); + this->table_id_ = fm->table_id; + this->command_ = fm->command; + this->idle_timeout_ = ntoh16(fm->idle_timeout); + this->hard_timeout_ = ntoh16(fm->hard_timeout); + this->priority_ = ntoh16(fm->priority); + this->buffer_id_ = ntoh32(fm->buffer_id); + this->out_port_ = ntoh32(fm->out_port); + this->out_group_ = ntoh32(fm->out_group); + this->flags_ = ntoh16(fm->flags); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match)); + err = this->match_.unpack(p); + if (err) { + return err; + } + this->instructions_.length( + this->length_ + - ((sizeof(struct of13::ofp_flow_mod) + - sizeof(struct of13::ofp_match)) + + ROUND_UP(this->match_.length(), 8))); + p += ROUND_UP(this->match_.length(), 8); + this->instructions_.unpack(p); + return 0; +} + +OXMTLV * FlowMod::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void FlowMod::match(of13::Match match) { + this->match_ = match; + this->length_ += this->match_.length(); +} + +void FlowMod::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void FlowMod::add_oxm_field(OXMTLV *field) { + this->match_.add_oxm_field(field); +} + +void FlowMod::instructions(InstructionSet instructions) { + this->instructions_ = instructions; + this->length_ += instructions.length(); +} + +void FlowMod::add_instruction(Instruction &inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst.length(); +} + +void FlowMod::add_instruction(Instruction* inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst->length(); +} + +FlowRemoved::FlowRemoved() + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED), + table_id_(0), + hard_timeout_(0) { +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count) + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count), + table_id_(table_id), + hard_timeout_(hard_timeout) { +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count, of13::Match match) + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count) { + this->table_id_ = table_id; + this->hard_timeout_ = hard_timeout; + this->match_ = match; +} + +uint16_t FlowRemoved::length() { + return sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); +} + +bool FlowRemoved::operator==(const FlowRemoved &other) const { + return ((FlowRemovedCommon::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->match_ == other.match_)); +} + +bool FlowRemoved::operator!=(const FlowRemoved &other) const { + return !(*this == other); +} + +uint8_t* FlowRemoved::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP(this->match_.length(), 8) - this->match_.length(); + struct of13::ofp_flow_removed *fr = (struct of13::ofp_flow_removed*) buffer; + fr->cookie = hton64(this->cookie_); + fr->priority = hton16(this->priority_); + fr->reason = this->reason_; + fr->table_id = this->table_id_; + fr->duration_sec = hton32(this->duration_sec_); + fr->duration_nsec = hton32(this->duration_nsec_); + fr->idle_timeout = hton16(this->idle_timeout_); + fr->hard_timeout = hton32(this->hard_timeout_); + fr->packet_count = hton64(this->packet_count_); + fr->byte_count = hton64(this->byte_count_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error FlowRemoved::unpack(uint8_t *buffer) { + struct of13::ofp_flow_removed *fr = (struct of13::ofp_flow_removed*) buffer; + OFMsg::unpack(buffer); + this->cookie_ = ntoh64(fr->cookie); + this->priority_ = ntoh16(fr->priority); + this->reason_ = fr->reason; + this->table_id_ = fr->table_id; + this->duration_sec_ = ntoh32(fr->duration_sec); + this->duration_nsec_ = ntoh32(fr->duration_nsec); + this->idle_timeout_ = ntoh16(fr->idle_timeout); + this->hard_timeout_ = ntoh32(fr->hard_timeout); + this->packet_count_ = ntoh64(fr->packet_count); + this->byte_count_ = ntoh64(fr->byte_count); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +PortStatus::PortStatus() + : PortStatusCommon(of13::OFP_VERSION, of13::OFPT_PORT_STATUS) { + this->length_ = sizeof(struct of13::ofp_port_status); +} + +PortStatus::PortStatus(uint32_t xid, uint8_t reason, of13::Port desc) + : PortStatusCommon(of13::OFP_VERSION, of13::OFPT_PORT_STATUS, xid, reason), + desc_(desc) { + this->length_ = sizeof(struct of13::ofp_port_status); +} + +bool PortStatus::operator==(const PortStatus &other) const { + return ((PortStatusCommon::operator==(other)) + && (this->desc_ == other.desc_)); +} + +bool PortStatus::operator!=(const PortStatus &other) const { + return !(*this == other); +} + +uint8_t* PortStatus::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_port_status *ps = (struct of13::ofp_port_status *) buffer; + ps->reason = this->reason_; + memset(ps->pad, 0x0, 7); + this->desc_.pack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return buffer; +} + +of_error PortStatus::unpack(uint8_t *buffer) { + struct of13::ofp_port_status *ps = (struct of13::ofp_port_status *) buffer; + OFMsg::unpack(buffer); + this->reason_ = ps->reason; + this->desc_.unpack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return 0; +} + +PortMod::PortMod() + : PortModCommon(of13::OFP_VERSION, of13::OFPT_PORT_MOD) { + this->length_ = sizeof(struct of13::ofp_port_mod); +} + +PortMod::PortMod(uint32_t xid, uint32_t port_no, EthAddress hw_addr, + uint32_t config, uint32_t mask, uint32_t advertise) + : PortModCommon(of13::OFP_VERSION, of13::OFPT_PORT_MOD, xid, hw_addr, + config, mask, advertise), + port_no_(port_no) { + this->length_ = sizeof(struct of13::ofp_port_mod); +} + +bool PortMod::operator==(const PortMod &other) const { + return ((PortModCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortMod::operator!=(const PortMod &other) const { + return !(*this == other); +} + +uint8_t* PortMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_port_mod *pm = (struct of13::ofp_port_mod *) buffer; + pm->port_no = hton32(this->port_no_); + memset(pm->pad, 0x0, 4); + memcpy(pm->hw_addr, hw_addr_.get_data(), OFP_ETH_ALEN); + memset(pm->pad, 0x0, 2); + pm->config = hton32(this->config_); + pm->mask = hton32(this->mask_); + pm->advertise = hton32(this->advertise_); + memset(pm->pad, 0x0, 4); + return buffer; +} + +of_error PortMod::unpack(uint8_t* buffer) { + struct of13::ofp_port_mod *pm = (struct of13::ofp_port_mod *) buffer; + if (pm->header.length < sizeof(struct of13::ofp_port_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + OFMsg::unpack(buffer); + this->port_no_ = ntoh32(pm->port_no); + this->hw_addr_ = EthAddress(pm->hw_addr); + this->config_ = ntoh32(pm->config); + this->mask_ = ntoh32(pm->mask); + this->advertise_ = ntoh32(pm->advertise); + return 0; +} + +GroupMod::GroupMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD) { + this->length_ = sizeof(struct of13::ofp_group_mod); +} + +GroupMod::GroupMod(uint32_t xid, uint16_t command, uint8_t type, + uint32_t group_id) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD, xid), + command_(command), + group_type_(type), + group_id_(group_id) { + this->length_ = sizeof(struct of13::ofp_group_mod); +} + +GroupMod::GroupMod(uint32_t xid, uint16_t command, uint8_t type, + uint32_t group_id, std::vector buckets) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD, xid) { + this->command_ = command; + this->group_type_ = type; + this->group_id_ = group_id; + this->buckets_ = buckets; + this->length_ = sizeof(struct of13::ofp_group_mod) + buckets_len(); +} + +bool GroupMod::operator==(const GroupMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) + && (this->group_type_ == other.group_type_) + && (this->group_id_ == other.group_id_) + && (this->buckets_ == other.buckets_)); +} + +bool GroupMod::operator!=(const GroupMod &other) const { + return !(*this == other); +} + +void GroupMod::buckets(std::vector buckets) { + this->buckets_ = buckets; + this->length_ += buckets_len(); +} + +void GroupMod::add_bucket(Bucket bucket) { + this->buckets_.push_back(bucket); + this->length_ += bucket.len(); +} + +size_t GroupMod::buckets_len() { + size_t len = 0; + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + len += it->len(); + } + return len; +} +; + +uint8_t* GroupMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_group_mod *gm = (struct of13::ofp_group_mod*) buffer; + gm->command = hton16(this->command_); + gm->type = this->group_type_; + gm->group_id = hton32(this->group_id_); + uint8_t *p = buffer + sizeof(struct ofp_group_mod); + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error GroupMod::unpack(uint8_t *buffer) { + struct of13::ofp_group_mod *gm = (struct of13::ofp_group_mod*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_group_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->command_ = ntoh16(gm->command); + this->group_type_ = gm->type; + this->group_id_ = ntoh32(gm->group_id); + size_t len = this->length_ - sizeof(struct ofp_group_mod); + uint8_t *p = buffer + sizeof(struct ofp_group_mod); + while (len) { + Bucket bucket; + bucket.unpack(p); + this->buckets_.push_back(bucket); + p += bucket.len(); + len -= bucket.len(); + } + return 0; +} + +TableMod::TableMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_TABLE_MOD) { + this->length_ = sizeof(struct of13::ofp_table_mod); +} + +TableMod::TableMod(uint32_t xid, uint8_t table_id, uint32_t config) + : OFMsg(of13::OFP_VERSION, of13::OFPT_TABLE_MOD, xid), + table_id_(table_id), + config_(config) { + this->length_ = sizeof(struct of13::ofp_table_mod); +} + +bool TableMod::operator==(const TableMod &other) const { + return ((OFMsg::operator==(other)) && (this->table_id_ == other.table_id_) + && (this->config_ == other.config_)); +} + +bool TableMod::operator!=(const TableMod &other) const { + return !(*this == other); +} + +uint8_t* TableMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_table_mod *tm = (struct of13::ofp_table_mod*) buffer; + tm->table_id = this->table_id_; + memset(tm->pad, 0x0, 3); + tm->config = hton32(this->config_); + return buffer; +} + +of_error TableMod::unpack(uint8_t *buffer) { + struct of13::ofp_table_mod *tm = (struct of13::ofp_table_mod*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_table_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = tm->table_id; + this->config_ = ntoh32(tm->config); + return 0; +} + +MultipartRequest::MultipartRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +MultipartRequest::MultipartRequest(uint16_t type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST), + mpart_type_(type) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +MultipartRequest::MultipartRequest(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST, xid), + mpart_type_(type), + flags_(flags) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +bool MultipartRequest::operator==(const MultipartRequest &other) const { + return ((OFMsg::operator==(other)) + && (this->mpart_type_ == other.mpart_type_) + && (this->length_ == other.length_)); +} + +bool MultipartRequest::operator!=(const MultipartRequest &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_multipart_request * mr = + (struct of13::ofp_multipart_request *) buffer; + mr->type = hton16(this->mpart_type_); + mr->flags = hton16(this->flags_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequest::unpack(uint8_t *buffer) { + struct of13::ofp_multipart_request * mr = + (struct of13::ofp_multipart_request *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->mpart_type_ = ntoh16(mr->type); + this->flags_ = ntoh16(mr->flags); + return 0; +} + +MultipartReply::MultipartReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY) { + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +MultipartReply::MultipartReply(uint16_t type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY), + mpart_type_(type) { + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +MultipartReply::MultipartReply(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY, xid), + mpart_type_(type), + flags_(flags) { + this->mpart_type_ = type; + this->flags_ = flags; + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +bool MultipartReply::operator==(const MultipartReply &other) const { + return ((OFMsg::operator==(other)) + && (this->mpart_type_ == other.mpart_type_) + && (this->flags_ == other.flags_)); +} + +bool MultipartReply::operator!=(const MultipartReply &other) const { + return !(*this == other); +} + +uint8_t* MultipartReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_multipart_reply * mr = + (struct of13::ofp_multipart_reply *) buffer; + mr->type = hton16(this->mpart_type_); + mr->flags = hton16(this->flags_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartReply::unpack(uint8_t *buffer) { + struct of13::ofp_multipart_reply * mr = + (struct of13::ofp_multipart_reply *) buffer; + OFMsg::unpack(buffer); + this->mpart_type_ = ntoh16(mr->type); + this->flags_ = ntoh16(mr->flags); + return 0; +} + +MultipartRequestDesc::MultipartRequestDesc() + : MultipartRequest(OFPMP_DESC) { +} + +MultipartRequestDesc::MultipartRequestDesc(uint32_t xid, uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_DESC, flags) { +} + +uint8_t* MultipartRequestDesc::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestDesc::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyDesc::MultipartReplyDesc() + : MultipartReply(of13::OFPMP_DESC) { + this->length_ += sizeof(struct ofp_desc); +} + +MultipartReplyDesc::MultipartReplyDesc(uint32_t xid, uint16_t flags, + SwitchDesc desc) + : MultipartReply(xid, of13::OFPMP_DESC, flags) { + this->desc_ = desc; + this->length_ += sizeof(struct ofp_desc); +} + +MultipartReplyDesc::MultipartReplyDesc(uint32_t xid, uint16_t flags, + std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc) + : MultipartReply(xid, of13::OFPMP_DESC, flags), + desc_(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) { + + this->length_ += sizeof(struct ofp_desc); +} + +bool MultipartReplyDesc::operator==(const MultipartReplyDesc &other) const { + return ((MultipartReply::operator==(other)) && (this->desc_ == other.desc_)); +} + +bool MultipartReplyDesc::operator!=(const MultipartReplyDesc &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyDesc::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->desc_.pack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyDesc::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->desc_.unpack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestFlow::MultipartRequestFlow() + : MultipartRequest(OFPMP_FLOW) { + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestFlow::MultipartRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask) + : MultipartRequest(xid, of13::OFPMP_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask) { + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestFlow::MultipartRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match) + : MultipartRequest(xid, of13::OFPMP_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask), + match_(match) { + + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + match.length(); +} + +bool MultipartRequestFlow::operator==(const MultipartRequestFlow &other) const { + return ((MultipartRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->cookie_ == other.cookie_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->match_ == other.match_)); +} + +bool MultipartRequestFlow::operator!=(const MultipartRequestFlow &other) const { + return !(*this == other); +} + +void MultipartRequestFlow::match(of13::Match match) { + this->match_ = match; + this->length_ += match.length(); +} + +void MultipartRequestFlow::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void MultipartRequestFlow::add_oxm_field(OXMTLV* field) { + this->match_.add_oxm_field(field); +} + +uint8_t* MultipartRequestFlow::pack() { + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length(), 8) + - (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length()); + this->length_ = sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_flow_stats_request *fs = + (struct of13::ofp_flow_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + fs->table_id = this->table_id_; + memset(fs->pad, 0x0, 3); + fs->out_port = hton32(this->out_port_); + fs->out_group = hton32(this->out_group_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->cookie_mask = hton64(this->cookie_mask_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error MultipartRequestFlow::unpack(uint8_t *buffer) { + struct of13::ofp_flow_stats_request *fs = + (struct of13::ofp_flow_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = ntoh32(fs->out_port); + this->out_group_ = ntoh32(fs->out_group); + this->cookie_ = ntoh64(fs->cookie); + this->cookie_mask_ = ntoh64(fs->cookie_mask); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +MultipartReplyFlow::MultipartReplyFlow() + : MultipartReply(OFPMP_FLOW) { +} + +MultipartReplyFlow::MultipartReplyFlow(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_FLOW, flags) { +} + +MultipartReplyFlow::MultipartReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats) + : MultipartReply(xid, of13::OFPMP_FLOW, flags), + flow_stats_(flow_stats) { + size_t stats_len = 0; + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + stats_len += it->length(); + } + this->length_ += stats_len; +} + +bool MultipartReplyFlow::operator==(const MultipartReplyFlow &other) const { + return ((MultipartReply::operator==(other)) + && (this->flow_stats_ == other.flow_stats_)); +} + +bool MultipartReplyFlow::operator!=(const MultipartReplyFlow &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyFlow::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyFlow::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + of13::FlowStats stat; + stat.unpack(p); + this->flow_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void MultipartReplyFlow::flow_stats(std::vector flow_stats) { + this->flow_stats_ = flow_stats; + this->length_ += this->flow_stats_.size() + * sizeof(struct of13::ofp_flow_stats); +} + +void MultipartReplyFlow::add_flow_stats(of13::FlowStats stats) { + this->flow_stats_.push_back(stats); + this->length_ += stats.length(); +} + +MultipartRequestAggregate::MultipartRequestAggregate() + : MultipartRequest(OFPMP_AGGREGATE) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestAggregate::MultipartRequestAggregate(uint32_t xid, + uint16_t flags, uint8_t table_id, uint32_t out_port, uint32_t out_group, + uint64_t cookie, uint64_t cookie_mask) + : MultipartRequest(xid, of13::OFPMP_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestAggregate::MultipartRequestAggregate(uint32_t xid, + uint16_t flags, uint8_t table_id, uint32_t out_port, uint32_t out_group, + uint64_t cookie, uint64_t cookie_mask, of13::Match match) + : MultipartRequest(xid, of13::OFPMP_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask), + match_(match) { + this->length_ = length(); +} + +bool MultipartRequestAggregate::operator==( + const MultipartRequestAggregate &other) const { + return ((MultipartRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->cookie_ == other.cookie_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->match_ == other.match_)); +} + +bool MultipartRequestAggregate::operator!=( + const MultipartRequestAggregate &other) const { + return !(*this == other); +} + +uint16_t MultipartRequestAggregate::length() { + return sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); +} + +void MultipartRequestAggregate::match(of13::Match match) { + this->match_ = match; + this->length_ += ROUND_UP(match_.length(), 8); +} + +void MultipartRequestAggregate::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void MultipartRequestAggregate::add_oxm_field(OXMTLV* field) { + this->match_.add_oxm_field(field); +} + +uint8_t* MultipartRequestAggregate::pack() { + size_t padding = length() + - (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length()); + this->length_ = length(); + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_aggregate_stats_request *fs = + (struct of13::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + fs->table_id = this->table_id_; + memset(fs->pad, 0x0, 3); + fs->out_port = hton32(this->out_port_); + fs->out_group = hton32(this->out_group_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->cookie_mask = hton64(this->cookie_mask_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error MultipartRequestAggregate::unpack(uint8_t *buffer) { + struct of13::ofp_aggregate_stats_request *fs = + (struct of13::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = ntoh32(fs->out_port); + this->out_group_ = ntoh32(fs->out_group); + this->cookie_ = ntoh64(fs->cookie); + this->cookie_mask_ = ntoh64(fs->cookie_mask); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +MultipartReplyAggregate::MultipartReplyAggregate() + : MultipartReply(OFPMP_AGGREGATE) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_reply); +} + +MultipartReplyAggregate::MultipartReplyAggregate(uint32_t xid, uint16_t flags, + uint64_t packet_count, uint64_t byte_count, uint32_t flow_count) + : MultipartReply(xid, of13::OFPMP_AGGREGATE, flags), + packet_count_(packet_count), + byte_count_(byte_count), + flow_count_(flow_count) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_reply); +} + +bool MultipartReplyAggregate::operator==( + const MultipartReplyAggregate &other) const { + return ((MultipartReply::operator==(other)) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->flow_count_ == other.flow_count_)); +} + +bool MultipartReplyAggregate::operator!=( + const MultipartReplyAggregate &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyAggregate::pack() { + uint8_t* buffer = MultipartReply::pack(); + struct of13::ofp_aggregate_stats_reply *ar = + (struct of13::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + ar->packet_count = hton64(this->packet_count_); + ar->byte_count = hton64(this->byte_count_); + ar->flow_count = hton32(this->flow_count_); + return buffer; +} + +of_error MultipartReplyAggregate::unpack(uint8_t *buffer) { + struct of13::ofp_aggregate_stats_reply *ar = + (struct of13::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartReply::unpack(buffer); + this->packet_count_ = ntoh64(ar->packet_count); + this->byte_count_ = ntoh64(ar->byte_count); + this->flow_count_ = ntoh32(ar->flow_count); + return 0; +} + +MultipartRequestTable::MultipartRequestTable() + : MultipartRequest(OFPMP_TABLE) { +} + +MultipartRequestTable::MultipartRequestTable(uint32_t xid, uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_TABLE, flags) { +} + +uint8_t* MultipartRequestTable::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestTable::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyTable::MultipartReplyTable() + : MultipartReply(OFPMP_TABLE) { +} + +MultipartReplyTable::MultipartReplyTable(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_TABLE, flags) { +} + +MultipartReplyTable::MultipartReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats) + : MultipartReply(xid, of13::OFPMP_TABLE, flags), + table_stats_(table_stats) { + this->length_ += table_stats.size() * sizeof(struct of13::ofp_table_stats); + +} + +bool MultipartReplyTable::operator==(const MultipartReplyTable &other) const { + return ((MultipartReply::operator==(other)) + && (this->table_stats_ == other.table_stats_)); +} + +bool MultipartReplyTable::operator!=(const MultipartReplyTable &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyTable::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->table_stats_.begin(); it != this->table_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_table_stats); + } + return buffer; +} + +of_error MultipartReplyTable::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_request); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_request); + while (len > 0) { + TableStats stat; + stat.unpack(p); + this->table_stats_.push_back(stat); + p += sizeof(struct of13::ofp_table_stats); + len -= sizeof(struct of13::ofp_table_stats); + } + return 0; +} + +void MultipartReplyTable::table_stats( + std::vector table_stats) { + this->table_stats_ = table_stats; + this->length_ += table_stats.size() * sizeof(struct of13::ofp_table_stats); +} + +void MultipartReplyTable::add_table_stat(of13::TableStats stat) { + this->table_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_table_stats); +} + +MultipartRequestPortStats::MultipartRequestPortStats() + : MultipartRequest(OFPMP_PORT_STATS) { + this->length_ += sizeof(struct of13::ofp_port_stats_request); +} + +MultipartRequestPortStats::MultipartRequestPortStats(uint32_t xid, + uint16_t flags, uint32_t port_no) + : MultipartRequest(xid, of13::OFPMP_PORT_STATS, flags), + port_no_(port_no) { + this->length_ += sizeof(struct of13::ofp_port_stats_request); + +} +; + +bool MultipartRequestPortStats::operator==( + const MultipartRequestPortStats &other) const { + return ((MultipartRequest::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool MultipartRequestPortStats::operator!=( + const MultipartRequestPortStats &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestPortStats::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_port_stats_request *ps = + (struct of13::ofp_port_stats_request *) (buffer + + sizeof(struct of13::ofp_multipart_request)); + ps->port_no = hton32(this->port_no_); + memset(ps->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestPortStats::unpack(uint8_t *buffer) { + struct of13::ofp_port_stats_request *ps = + (struct of13::ofp_port_stats_request *) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_port_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh32(ps->port_no); + return 0; +} + +MultipartReplyPortStats::MultipartReplyPortStats() + : MultipartReply(OFPMP_PORT_STATS) { +} + +MultipartReplyPortStats::MultipartReplyPortStats(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_PORT_STATS, flags) { +} + +MultipartReplyPortStats::MultipartReplyPortStats(uint32_t xid, uint16_t flags, + std::vector port_stats) + : MultipartReply(xid, of13::OFPMP_PORT_STATS, flags) { + this->port_stats_ = port_stats; + this->length_ = port_stats.size() * sizeof(struct of13::ofp_port_stats); + +} + +bool MultipartReplyPortStats::operator==( + const MultipartReplyPortStats &other) const { + return ((MultipartReply::operator==(other)) + && (this->port_stats_ == other.port_stats_)); +} + +bool MultipartReplyPortStats::operator!=( + const MultipartReplyPortStats &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyPortStats::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = this->port_stats_.begin(); + it != this->port_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_port_stats); + } + return buffer; +} + +of_error MultipartReplyPortStats::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_request); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_request); + while (len > 0) { + of13::PortStats stat; + stat.unpack(p); + this->port_stats_.push_back(stat); + p += sizeof(struct of13::ofp_port_stats); + len -= sizeof(struct of13::ofp_port_stats); + } + return 0; +} + +void MultipartReplyPortStats::port_stats( + std::vector port_stats) { + this->port_stats_ = port_stats; + this->length_ += port_stats.size() * sizeof(struct of13::ofp_port_stats); +} + +void MultipartReplyPortStats::add_port_stat(of13::PortStats stat) { + this->port_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_port_stats); +} + +MultipartRequestQueue::MultipartRequestQueue() + : MultipartRequest(OFPMP_QUEUE) { + this->length_ += sizeof(struct of13::ofp_queue_stats_request); +} + +MultipartRequestQueue::MultipartRequestQueue(uint32_t xid, uint16_t flags, + uint32_t port_no, uint32_t queue_id) + : MultipartRequest(xid, of13::OFPMP_QUEUE, flags), + port_no_(port_no), + queue_id_(queue_id) { + this->length_ += sizeof(struct of13::ofp_queue_stats_request); +} + +bool MultipartRequestQueue::operator==( + const MultipartRequestQueue &other) const { + return ((MultipartRequest::operator==(other)) + && (this->queue_id_ == other.queue_id_) + && (this->port_no_ == other.port_no_)); +} + +bool MultipartRequestQueue::operator!=( + const MultipartRequestQueue &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestQueue::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_queue_stats_request* qs = + (of13::ofp_queue_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + qs->port_no = hton32(this->port_no_); + qs->queue_id = hton32(this->queue_id_); + return buffer; +} + +of_error MultipartRequestQueue::unpack(uint8_t *buffer) { + struct of13::ofp_queue_stats_request* qs = + (of13::ofp_queue_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_queue_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh32(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + return 0; +} + +MultipartReplyQueue::MultipartReplyQueue() + : MultipartReply(OFPMP_QUEUE) { +} + +MultipartReplyQueue::MultipartReplyQueue(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_QUEUE, flags) { +} + +MultipartReplyQueue::MultipartReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats) + : MultipartReply(xid, of13::OFPMP_QUEUE, flags), + queue_stats_(queue_stats) { + this->length_ += queue_stats.size() * sizeof(struct of13::ofp_queue_stats); +} + +bool MultipartReplyQueue::operator==(const MultipartReplyQueue &other) const { + return ((MultipartReply::operator==(other)) + && (this->queue_stats_ == other.queue_stats_)); +} + +bool MultipartReplyQueue::operator!=(const MultipartReplyQueue &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyQueue::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->queue_stats_.begin(); it != this->queue_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_queue_stats); + } + return buffer; +} + +of_error MultipartReplyQueue::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::QueueStats stat; + stat.unpack(p); + this->queue_stats_.push_back(stat); + p += sizeof(struct of13::ofp_queue_stats); + len -= sizeof(struct of13::ofp_queue_stats); + } + return 0; +} + +void MultipartReplyQueue::queue_stats( + std::vector queue_stats) { + this->queue_stats_ = queue_stats; + this->length_ += queue_stats.size() * sizeof(struct of13::ofp_queue_stats); +} + +void MultipartReplyQueue::add_queue_stat(of13::QueueStats stat) { + this->queue_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_queue_stats); +} + +MultipartRequestGroup::MultipartRequestGroup() + : MultipartRequest(OFPMP_GROUP) { + this->length_ += sizeof(struct of13::ofp_group_stats_request); +} + +MultipartRequestGroup::MultipartRequestGroup(uint32_t xid, uint16_t flags, + uint32_t group_id) + : MultipartRequest(xid, of13::OFPMP_GROUP, flags), + group_id_(group_id) { + this->length_ += sizeof(struct of13::ofp_group_stats_request); +} + +bool MultipartRequestGroup::operator==( + const MultipartRequestGroup &other) const { + return ((MultipartRequest::operator==(other)) + && (this->group_id_ == other.group_id_)); +} + +bool MultipartRequestGroup::operator!=( + const MultipartRequestGroup &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestGroup::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_group_stats_request* gs = + (of13::ofp_group_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + gs->group_id = hton32(this->group_id_); + memset(gs->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestGroup::unpack(uint8_t *buffer) { + struct of13::ofp_group_stats_request* gs = + (of13::ofp_group_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_group_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->group_id_ = ntoh32(gs->group_id); + return 0; +} + +MultipartReplyGroup::MultipartReplyGroup() + : MultipartReply(OFPMP_GROUP) { +} + +MultipartReplyGroup::MultipartReplyGroup(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_GROUP, flags) { +} + +MultipartReplyGroup::MultipartReplyGroup(uint32_t xid, uint16_t flags, + std::vector group_stats) + : MultipartReply(xid, of13::OFPMP_GROUP, flags), + group_stats_(group_stats) { + this->length_ += group_stats_len(); +} + +bool MultipartReplyGroup::operator==(const MultipartReplyGroup &other) const { + return ((MultipartReply::operator==(other)) + && (this->group_stats_ == other.group_stats_)); +} + +bool MultipartReplyGroup::operator!=(const MultipartReplyGroup &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroup::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->group_stats_.begin(); it != this->group_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyGroup::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::GroupStats stat; + stat.unpack(p); + this->group_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void MultipartReplyGroup::group_stats( + std::vector group_stats) { + this->group_stats_ = group_stats; + this->length_ += group_stats_len(); +} + +void MultipartReplyGroup::add_group_stats(of13::GroupStats stat) { + this->group_stats_.push_back(stat); + this->length_ += stat.length(); +} + +size_t MultipartReplyGroup::group_stats_len() { + size_t len; + for (std::vector::iterator it = + this->group_stats_.begin(); it != this->group_stats_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestGroupDesc::MultipartRequestGroupDesc() + : MultipartRequest(OFPMP_GROUP_DESC) { +} + +MultipartRequestGroupDesc::MultipartRequestGroupDesc(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_GROUP_DESC, flags) { +} + +uint8_t* MultipartRequestGroupDesc::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestGroupDesc::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc() + : MultipartReply(OFPMP_GROUP_DESC) { +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_GROUP_DESC, flags) { +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc(uint32_t xid, uint16_t flags, + std::vector group_desc) + : MultipartReply(xid, of13::OFPMP_GROUP_DESC, flags), + group_desc_(group_desc) { + this->length_ += desc_len(); +} + +bool MultipartReplyGroupDesc::operator==( + const MultipartReplyGroupDesc &other) const { + return ((MultipartReply::operator==(other)) + && (this->group_desc_ == other.group_desc_)); +} + +bool MultipartReplyGroupDesc::operator!=( + const MultipartReplyGroupDesc &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroupDesc::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->group_desc_.begin(); + it != this->group_desc_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyGroupDesc::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::GroupDesc desc; + desc.unpack(p); + this->group_desc_.push_back(desc); + p += desc.length(); + len -= desc.length(); + } + return 0; +} + +void MultipartReplyGroupDesc::group_desc( + std::vector group_desc) { + this->group_desc_ = group_desc; + this->length_ += desc_len(); +} + +void MultipartReplyGroupDesc::add_group_desc(of13::GroupDesc desc) { + this->group_desc_.push_back(desc); + this->length_ += desc.length(); +} + +size_t MultipartReplyGroupDesc::desc_len() { + size_t len = 0; + for (std::vector::iterator it = this->group_desc_.begin(); + it != this->group_desc_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestGroupFeatures::MultipartRequestGroupFeatures() + : MultipartRequest(OFPMP_GROUP_FEATURES) { +} + +MultipartRequestGroupFeatures::MultipartRequestGroupFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_GROUP_FEATURES, flags) { +} + +uint8_t* MultipartRequestGroupFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestGroupFeatures::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyGroupFeatures::MultipartReplyGroupFeatures() + : MultipartReply(OFPMP_GROUP_FEATURES) { +} + +MultipartReplyGroupFeatures::MultipartReplyGroupFeatures(uint32_t xid, + uint16_t flags, of13::GroupFeatures features) + : MultipartReply(xid, of13::OFPMP_GROUP_FEATURES, flags), + features_(features) { + this->features_ = features; + this->length_ += sizeof(struct of13::ofp_group_features); +} + +bool MultipartReplyGroupFeatures::operator==( + const MultipartReplyGroupFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->features_ == other.features_)); +} + +bool MultipartReplyGroupFeatures::operator!=( + const MultipartReplyGroupFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroupFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->features_.pack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyGroupFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->features_.unpack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestMeter::MultipartRequestMeter() + : MultipartRequest(OFPMP_METER) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +MultipartRequestMeter::MultipartRequestMeter(uint32_t xid, uint16_t flags, + uint32_t meter_id) + : MultipartRequest(xid, of13::OFPMP_METER, flags), + meter_id_(meter_id) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +bool MultipartRequestMeter::operator==( + const MultipartRequestMeter &other) const { + return ((MultipartRequest::operator==(other)) + && (this->meter_id_ == other.meter_id_)); +} + +bool MultipartRequestMeter::operator!=( + const MultipartRequestMeter &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestMeter::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + mr->meter_id = hton32(this->meter_id_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestMeter::unpack(uint8_t *buffer) { + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_meter_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->meter_id_ = ntoh32(mr->meter_id); + return 0; +} + +MultipartReplyMeter::MultipartReplyMeter() + : MultipartReply(OFPMP_METER) { +} + +MultipartReplyMeter::MultipartReplyMeter(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_METER, flags) { +} + +MultipartReplyMeter::MultipartReplyMeter(uint32_t xid, uint16_t flags, + std::vector meter_stats) + : MultipartReply(xid, of13::OFPMP_METER, flags), + meter_stats_(meter_stats) { + this->length_ += meter_stats_len(); +} + +bool MultipartReplyMeter::operator==(const MultipartReplyMeter &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_stats_ == other.meter_stats_)); +} + +bool MultipartReplyMeter::operator!=(const MultipartReplyMeter &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeter::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->meter_stats_.begin(); it != this->meter_stats_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error MultipartReplyMeter::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::MeterStats stat; + stat.unpack(p); + this->meter_stats_.push_back(stat); + p += stat.len(); + len -= stat.len(); + } + return 0; +} + +void MultipartReplyMeter::meter_stats( + std::vector meter_stats) { + this->meter_stats_ = meter_stats; + this->length_ += meter_stats_len(); +} + +void MultipartReplyMeter::add_meter_stats(of13::MeterStats stat) { + this->meter_stats_.push_back(stat); + this->length_ += stat.len(); +} + +size_t MultipartReplyMeter::meter_stats_len() { + size_t len; + for (std::vector::iterator it = + this->meter_stats_.begin(); it != this->meter_stats_.end(); ++it) { + len += it->len(); + } + return len; +} + +MultipartRequestMeterConfig::MultipartRequestMeterConfig() + : MultipartRequest(OFPMP_METER_CONFIG) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +MultipartRequestMeterConfig::MultipartRequestMeterConfig(uint32_t xid, + uint16_t flags, uint32_t meter_id) + : MultipartRequest(xid, of13::OFPMP_METER, flags), + meter_id_(meter_id) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +bool MultipartRequestMeterConfig::operator==( + const MultipartRequestMeterConfig &other) const { + return ((MultipartRequest::operator==(other)) + && (this->meter_id_ == other.meter_id_)); +} + +bool MultipartRequestMeterConfig::operator!=( + const MultipartRequestMeterConfig &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestMeterConfig::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + mr->meter_id = hton32(this->meter_id_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestMeterConfig::unpack(uint8_t *buffer) { + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_meter_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->meter_id_ = ntoh32(mr->meter_id); + return 0; +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig() + : MultipartReply(OFPMP_METER_CONFIG) { +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_METER_CONFIG, flags) { +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig(uint32_t xid, + uint16_t flags, std::vector meter_config) + : MultipartReply(xid, of13::OFPMP_METER_CONFIG, flags), + meter_config_(meter_config) { + this->length_ += meter_config_len(); +} + +bool MultipartReplyMeterConfig::operator==( + const MultipartReplyMeterConfig &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_config_ == other.meter_config_)); +} + +bool MultipartReplyMeterConfig::operator!=( + const MultipartReplyMeterConfig &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeterConfig::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->meter_config_.begin(); + it != this->meter_config_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyMeterConfig::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + MeterConfig conf; + conf.unpack(p); + this->meter_config_.push_back(conf); + p += conf.length(); + len -= conf.length(); + } + return 0; +} + +void MultipartReplyMeterConfig::meter_config( + std::vector meter_config) { + this->meter_config_ = meter_config; + this->length_ += meter_config_len(); +} + +void MultipartReplyMeterConfig::add_meter_config(MeterConfig config) { + this->meter_config_.push_back(config); + this->length_ += config.length(); +} + +size_t MultipartReplyMeterConfig::meter_config_len() { + size_t len; + for (std::vector::iterator it = this->meter_config_.begin(); + it != this->meter_config_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestMeterFeatures::MultipartRequestMeterFeatures() + : MultipartRequest(OFPMP_METER_FEATURES) { +} + +MultipartRequestMeterFeatures::MultipartRequestMeterFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_METER_FEATURES, flags) { +} + +uint8_t* MultipartRequestMeterFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestMeterFeatures::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyMeterFeatures::MultipartReplyMeterFeatures() + : MultipartReply(OFPMP_METER_FEATURES) { +} + +MultipartReplyMeterFeatures::MultipartReplyMeterFeatures(uint32_t xid, + uint16_t flags, MeterFeatures features) + : MultipartReply(xid, of13::OFPMP_METER_FEATURES, flags), + meter_features_(features) { + this->meter_features_ = features; + this->length_ += sizeof(struct of13::ofp_meter_features); +} + +bool MultipartReplyMeterFeatures::operator==( + const MultipartReplyMeterFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_features_ == other.meter_features_)); +} + +bool MultipartReplyMeterFeatures::operator!=( + const MultipartReplyMeterFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeterFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->meter_features_.pack( + buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyMeterFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->meter_features_.unpack( + buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures() + : MultipartRequest(OFPMP_TABLE_FEATURES) { +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_TABLE_FEATURES, flags) { +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures(uint32_t xid, + uint16_t flags, std::vector tables_features) + : MultipartRequest(xid, of13::OFPMP_TABLE_FEATURES, flags) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +bool MultipartRequestTableFeatures::operator==( + const MultipartRequestTableFeatures &other) const { + return ((MultipartRequest::operator==(other)) + && (this->tables_features_ == other.tables_features_)); +} + +bool MultipartRequestTableFeatures::operator!=( + const MultipartRequestTableFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestTableFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartRequestTableFeatures::unpack(uint8_t *buffer) { + MultipartRequest::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + TableFeatures features; + features.unpack(p); + this->tables_features_.push_back(features); + p += features.length(); + len -= features.length(); + } + return 0; +} + +void MultipartRequestTableFeatures::tables_features( + std::vector tables_features) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +void MultipartRequestTableFeatures::add_table_features( + TableFeatures table_feature) { + this->tables_features_.push_back(table_feature); + this->length_ += table_feature.length(); +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures() + : MultipartReply(OFPMP_TABLE_FEATURES) { +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_TABLE_FEATURES, flags) { +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures(uint32_t xid, + uint16_t flags, std::vector tables_features) + : MultipartReply(xid, of13::OFPMP_TABLE_FEATURES, flags) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +bool MultipartReplyTableFeatures::operator==( + const MultipartReplyTableFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->tables_features_ == other.tables_features_)); +} + +bool MultipartReplyTableFeatures::operator!=( + const MultipartReplyTableFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyTableFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyTableFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + TableFeatures features; + features.unpack(p); + this->tables_features_.push_back(features); + p += features.length(); + len -= features.length(); + } + return 0; +} + +void MultipartReplyTableFeatures::tables_features( + std::vector tables_features) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +void MultipartReplyTableFeatures::add_table_features( + TableFeatures table_feature) { + this->tables_features_.push_back(table_feature); + this->length_ += table_feature.length(); +} + +MultipartRequestPortDescription::MultipartRequestPortDescription() + : MultipartRequest(OFPMP_PORT_DESC) { +} + +MultipartRequestPortDescription::MultipartRequestPortDescription(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_PORT_DESC, flags) { +} + +uint8_t* MultipartRequestPortDescription::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestPortDescription::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyPortDescription::MultipartReplyPortDescription() + : MultipartReply(OFPMP_PORT_DESC) { +} + +MultipartReplyPortDescription::MultipartReplyPortDescription(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_PORT_DESC, flags) { +} + +MultipartReplyPortDescription::MultipartReplyPortDescription(uint32_t xid, + uint16_t flags, std::vector ports) + : MultipartReply(xid, of13::OFPMP_PORT_DESC, flags) { + this->ports_ = ports; + this->length_ += ports.size() * sizeof(struct of13::ofp_port); +} + +bool MultipartReplyPortDescription::operator==( + const MultipartReplyPortDescription &other) const { + return ((MultipartReply::operator==(other)) + && (this->ports_ == other.ports_)); +} + +bool MultipartReplyPortDescription::operator!=( + const MultipartReplyPortDescription &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyPortDescription::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->ports_.begin(); + it != this->ports_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_port); + } + return buffer; +} + +of_error MultipartReplyPortDescription::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + while (len) { + of13::Port port; + port.unpack(p); + this->ports_.push_back(port); + p += sizeof(struct of13::ofp_port); + len -= sizeof(struct of13::ofp_port); + } + return 0; +} + +void MultipartReplyPortDescription::ports(std::vector ports) { + this->ports_ = ports; + this->length_ += ports.size() * sizeof(struct of13::ofp_port); +} + +void MultipartReplyPortDescription::add_port(of13::Port port) { + this->ports_.push_back(port); + this->length_ += sizeof(struct of13::ofp_port); +} + +MultipartRequestExperimenter::MultipartRequestExperimenter() + : MultipartRequest(OFPMP_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +MultipartRequestExperimenter::MultipartRequestExperimenter(uint32_t xid, + uint16_t flags, uint32_t experimenter, uint32_t exp_type) + : MultipartRequest(xid, of13::OFPMP_EXPERIMENTER, flags), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +bool MultipartRequestExperimenter::operator==( + const MultipartRequestExperimenter &other) const { + return ((MultipartRequest::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool MultipartRequestExperimenter::operator!=( + const MultipartRequestExperimenter &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestExperimenter::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error MultipartRequestExperimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + MultipartRequest::unpack(buffer); + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +MultipartReplyExperimenter::MultipartReplyExperimenter() + : MultipartReply(OFPMP_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +MultipartReplyExperimenter::MultipartReplyExperimenter(uint32_t xid, + uint16_t flags, uint32_t experimenter, uint32_t exp_type) + : MultipartReply(xid, of13::OFPMP_EXPERIMENTER, flags), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +bool MultipartReplyExperimenter::operator==( + const MultipartReplyExperimenter &other) const { + return ((MultipartReply::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool MultipartReplyExperimenter::operator!=( + const MultipartReplyExperimenter &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyExperimenter::pack() { + uint8_t* buffer = MultipartReply::pack(); + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error MultipartReplyExperimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + MultipartReply::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_experimenter_multipart_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +QueueGetConfigRequest::QueueGetConfigRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REQUEST) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_request); +} + +QueueGetConfigRequest::QueueGetConfigRequest(uint32_t xid, uint32_t port) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REQUEST, xid), + port_(port) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_request); +} + +bool QueueGetConfigRequest::operator==( + const QueueGetConfigRequest &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_)); +} + +bool QueueGetConfigRequest::operator!=( + const QueueGetConfigRequest &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_queue_get_config_request * qc = + (struct of13::ofp_queue_get_config_request*) buffer; + qc->port = hton32(this->port_); + memset(qc->pad, 0x0, 4); + return buffer; +} + +of_error QueueGetConfigRequest::unpack(uint8_t *buffer) { + struct of13::ofp_queue_get_config_request * qc = + (struct of13::ofp_queue_get_config_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_queue_get_config_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_ = ntoh32(qc->port); + return 0; +} + +QueueGetConfigReply::QueueGetConfigReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint32_t port) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY, xid) { + this->port_ = port; + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port), + queues_(queues) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply) + + queues_len(); +} + +bool QueueGetConfigReply::operator==(const QueueGetConfigReply &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_) + && (this->queues_ == other.queues_)); +} + +bool QueueGetConfigReply::operator!=(const QueueGetConfigReply &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_queue_get_config_reply *qr = + (struct of13::ofp_queue_get_config_reply *) buffer; + qr->port = hton32(this->port_); + memset(qr->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of13::ofp_queue_get_config_reply); + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error QueueGetConfigReply::unpack(uint8_t *buffer) { + struct of13::ofp_queue_get_config_reply *qr = + (struct of13::ofp_queue_get_config_reply *) buffer; + OFMsg::unpack(buffer); + this->port_ = ntoh32(qr->port); + uint8_t *p = buffer + sizeof(struct of13::ofp_queue_get_config_reply); + size_t len = this->length_ + - sizeof(struct of13::ofp_queue_get_config_reply); + while (len) { + PacketQueue pq; + pq.unpack(p); + this->queues_.push_back(pq); + p += pq.len(); + len -= pq.len(); + } + return 0; +} + +void QueueGetConfigReply::queues(std::list queues) { + this->queues_ = queues; + this->length_ += queues_len(); +} + +void QueueGetConfigReply::add_queue(PacketQueue queue) { + this->queues_.push_back(queue); + this->length_ += queue.len(); +} + +size_t QueueGetConfigReply::queues_len() { + size_t len; + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + len += it->len(); + } + return len; +} + +BarrierRequest::BarrierRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REQUEST) { +} + +BarrierRequest::BarrierRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REQUEST, xid) { +} + +uint8_t* BarrierRequest::pack() { + return OFMsg::pack(); +} + +of_error BarrierRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +BarrierReply::BarrierReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REPLY) { +} + +BarrierReply::BarrierReply(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REPLY, xid) { +} + +uint8_t* BarrierReply::pack() { + return OFMsg::pack(); +} + +of_error BarrierReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + return 0; +} + +RoleRequest::RoleRequest() + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REQUEST) { +} + +RoleRequest::RoleRequest(uint32_t xid, uint32_t role, uint64_t generation_id) + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REQUEST, xid, role, + generation_id) { +} + +RoleReply::RoleReply() + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REPLY) { +} + +RoleReply::RoleReply(uint32_t xid, uint32_t role, uint64_t generation_id) + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REPLY, xid, role, + generation_id) { +} + +GetAsyncRequest::GetAsyncRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REQUEST) { +} + +GetAsyncRequest::GetAsyncRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REQUEST, xid) { +} + +uint8_t* GetAsyncRequest::pack() { + return OFMsg::pack(); +} + +of_error GetAsyncRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +GetAsyncReply::GetAsyncReply() + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY) { +} + +GetAsyncReply::GetAsyncReply(uint32_t xid) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY, xid) { +} + +GetAsyncReply::GetAsyncReply(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY, xid, + packet_in_mask, port_status_mask, flow_removed_mask) { + +} + +SetAsync::SetAsync() + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC) { +} + +SetAsync::SetAsync(uint32_t xid) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC, xid) { +} + +SetAsync::SetAsync(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC, xid, + packet_in_mask, port_status_mask, flow_removed_mask) { + +} + +MeterMod::MeterMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD) { + this->length_ = sizeof(struct of13::ofp_meter_mod); +} + +MeterMod::MeterMod(uint32_t xid, uint16_t command, uint16_t flags, + uint32_t meter_id) + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD, xid), + command_(command), + meter_id_(meter_id), + flags_(flags) { + this->length_ = sizeof(struct of13::ofp_meter_mod); +} + +MeterMod::MeterMod(uint32_t xid, uint16_t command, uint16_t flags, + uint32_t meter_id, MeterBandList bands) + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD, xid), + command_(command), + meter_id_(meter_id), + flags_(flags), + bands_(bands) { + this->length_ = sizeof(struct of13::ofp_meter_mod) + bands.length(); +} + +bool MeterMod::operator==(const MeterMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) + && (this->flags_ == other.flags_) + && (this->meter_id_ == other.meter_id_) + && (this->bands_ == other.bands_)); +} + +bool MeterMod::operator!=(const MeterMod &other) const { + return !(*this == other); +} + +uint8_t* MeterMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_meter_mod *mm = (struct of13::ofp_meter_mod *) buffer; + mm->command = hton16(this->command_); + mm->flags = hton16(this->flags_); + mm->meter_id = hton32(this->meter_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_mod); + this->bands_.pack(p); + return buffer; +} + +of_error MeterMod::unpack(uint8_t *buffer) { + struct of13::ofp_meter_mod *mm = (struct of13::ofp_meter_mod *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(of13::ofp_meter_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->command_ = ntoh16(mm->command); + this->flags_ = ntoh16(mm->flags); + this->meter_id_ = ntoh32(mm->meter_id); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_mod); + this->bands_.length(this->length_ - sizeof(struct of13::ofp_meter_mod)); + this->bands_.unpack(p); + return 0; +} + +void MeterMod::bands(MeterBandList bands) { + this->bands_ = bands; + this->length_ += bands.length(); +} + +void MeterMod::add_band(MeterBand* band) { + this->bands_.add_band(band); + this->length_ += band->len(); +} + +} // End of namespace of13 +} //End of namespace fluid_msg + diff --git a/src/ovs/libfluid-msg/ofcommon/action.cc b/src/ovs/libfluid-msg/ofcommon/action.cc new file mode 100644 index 00000000..3d811c26 --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/action.cc @@ -0,0 +1,226 @@ +#include "libfluid-msg/ofcommon/action.hh" + +namespace fluid_msg { + +Action::Action() + : type_(0), + length_(0) { +} + +Action::Action(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool Action::equals(const Action &other) { + return ((*this == other)); +} + +bool Action::operator==(const Action &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool Action::operator!=(const Action &other) const { + return !(*this == other); +} + +size_t Action::pack(uint8_t *buffer) { + struct ofp_action_header *ac = (struct ofp_action_header *) buffer; + ac->type = hton16(this->type_); + ac->len = hton16(this->length_); + memset(ac->pad, 0x0, 4); + return 0; +} + +of_error Action::unpack(uint8_t *buffer) { + struct ofp_action_header *ac = (struct ofp_action_header *) buffer; + this->type_ = ntoh16(ac->type); + this->length_ = ntoh16(ac->len); + return 0; +} + +ActionList::ActionList(std::list action_list) { + this->action_list_ = action_list_; + for (std::list::const_iterator it = action_list.begin(); + it != action_list.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +ActionList::ActionList(const ActionList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = other.action_list_.begin(); + it != other.action_list_.end(); ++it) { + this->action_list_.push_back((*it)->clone()); + } +} + +ActionList::~ActionList() { + this->action_list_.remove_if(Action::delete_all); +} + +bool ActionList::operator==(const ActionList &other) const { + std::list::const_iterator ot = other.action_list_.begin(); + for (std::list::const_iterator it = this->action_list_.begin(); + it != this->action_list_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool ActionList::operator!=(const ActionList &other) const { + return !(*this == other); +} + +size_t ActionList::pack(uint8_t *buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->action_list_.begin(), end = + this->action_list_.end(); it != end; ++it) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +of_error ActionList::unpack10(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of10_action(type); + act->unpack(p); + this->action_list_.push_back(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +of_error ActionList::unpack13(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of13_action(type); + act->unpack(p); + this->action_list_.push_back(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +ActionList& ActionList::operator=(ActionList other) { + swap(*this, other); + return *this; +} + +void swap(ActionList& first, ActionList& second) { + std::swap(first.length_, second.length_); + first.action_list_.swap(second.action_list_); +} + +void ActionList::add_action(Action &act) { + Action *actn = act.clone(); + this->action_list_.push_back(actn); + this->length_ += act.length(); +} + +void ActionList::add_action(Action * act) { + this->action_list_.push_back(act); + this->length_ += act->length(); +} + +ActionSet::ActionSet(std::set action_set) { + this->action_set_ = action_set_; + for (std::set::const_iterator it = action_set.begin(); + it != action_set.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +ActionSet::ActionSet(const ActionSet &other) { + this->length_ = other.length_; + for (std::set::const_iterator it = other.action_set_.begin(); + it != other.action_set_.end(); ++it) { + this->action_set_.insert((*it)->clone()); + } +} + +ActionSet::~ActionSet() { + for (std::set::const_iterator it = this->action_set_.begin(); + it != this->action_set_.end(); ++it) { + delete *it; + } +} + +bool ActionSet::operator==(const ActionSet &other) const { + std::set::const_iterator ot = other.action_set_.begin(); + for (std::set::const_iterator it = this->action_set_.begin(); + it != this->action_set_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool ActionSet::operator!=(const ActionSet &other) const { + return !(*this == other); +} + +size_t ActionSet::pack(uint8_t *buffer) { + uint8_t *p = buffer; + for (std::set::iterator it = this->action_set_.begin(), end = + this->action_set_.end(); it != end; ++it) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +/*OpenFlow 1.0 doesn't have actions sets, so we do not + * need to implement two unpack versions like we did for + * the ActionList */ +of_error ActionSet::unpack(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of13_action(type); + act->unpack(p); + this->action_set_.insert(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +ActionSet& ActionSet::operator=(ActionSet other) { + swap(*this, other); + return *this; +} + +void swap(ActionSet& first, ActionSet& second) { + + std::swap(first.length_, second.length_); + std::swap(first.action_set_, second.action_set_); +} + +void ActionSet::add_action(Action &act) { + Action *actn = act.clone(); + this->action_set_.insert(actn); + this->length_ += act.length(); +} + +void ActionSet::add_action(Action *act) { + this->action_set_.insert(act); + this->length_ += act->length(); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/ofcommon/common.cc b/src/ovs/libfluid-msg/ofcommon/common.cc new file mode 100644 index 00000000..2a974d9e --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/common.cc @@ -0,0 +1,436 @@ +#include "libfluid-msg/ofcommon/common.hh" + +namespace fluid_msg { + +PortCommon::PortCommon() + : hw_addr_(), + name_(), + config_(0), + state_(0), + curr_(0), + advertised_(0), + supported_(0), + peer_(0) { +} + +PortCommon::PortCommon(EthAddress hw_addr, std::string name, uint32_t config, + uint32_t state, uint32_t curr, uint32_t advertised, uint32_t supported, + uint32_t peer) + : hw_addr_(hw_addr), + name_(name), + config_(config), + state_(state), + curr_(curr), + advertised_(advertised), + supported_(supported), + peer_(peer) { +} + +bool PortCommon::operator==(const PortCommon &other) const { + return ((this->hw_addr_ == other.hw_addr_) && (this->name_ == other.name_) + && (this->config_ == other.config_) && (this->state_ == other.state_) + && (this->curr_ == other.curr_) + && (this->advertised_ == other.advertised_) + && (this->supported_ == other.supported_) + && (this->peer_ == other.peer_)); +} + +bool PortCommon::operator!=(const PortCommon &other) const { + return !(*this == other); +} + +QueueProperty::QueueProperty() + : property_(0), + len_(0) { +} + +QueueProperty::QueueProperty(uint16_t property) + : property_(property), + len_(sizeof(struct ofp_queue_prop_header)) { +} + +bool QueueProperty::equals(const QueueProperty &other) { + return ((*this == other)); +} + +bool QueueProperty::operator==(const QueueProperty &other) const { + return ((this->property_ == other.property_) && (this->len_ == other.len_)); +} + +bool QueueProperty::operator!=(const QueueProperty &other) const { + return !(*this == other); +} + +size_t QueueProperty::pack(uint8_t* buffer) { + struct ofp_queue_prop_header *qp = (struct ofp_queue_prop_header*) buffer; + qp->property = hton16(this->property_); + qp->len = hton16(this->len_); + return this->len_; +} + +of_error QueueProperty::unpack(uint8_t* buffer) { + struct ofp_queue_prop_header *qp = (struct ofp_queue_prop_header*) buffer; + this->property_ = ntoh16(qp->property); + this->len_ = ntoh16(qp->len); + return 0; +} + +QueuePropertyList::QueuePropertyList(std::list property_list) { + this->property_list_ = property_list_; + for (std::list::const_iterator it = property_list.begin(); + it != property_list.end(); ++it) { + this->length_ += (*it)->len(); + } +} + +QueuePropertyList::QueuePropertyList(const QueuePropertyList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = + other.property_list_.begin(); it != other.property_list_.end(); ++it) { + this->property_list_.push_back((*it)->clone()); + } +} + +QueuePropertyList::~QueuePropertyList() { + this->property_list_.remove_if(QueueProperty::delete_all); +} + +bool QueuePropertyList::operator==(const QueuePropertyList &other) const { + std::list::const_iterator ot = other.property_list_.begin(); + for (std::list::const_iterator it = + this->property_list_.begin(); it != this->property_list_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool QueuePropertyList::operator!=(const QueuePropertyList &other) const { + return !(*this == other); +} + +size_t QueuePropertyList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->property_list_.begin(), + end = this->property_list_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->len(); + } + return 0; +} + +of_error QueuePropertyList::unpack10(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + QueueProperty *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = QueueProperty::make_queue_of10_property(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->len(); + p += prop->len(); + } + return 0; +} + +of_error QueuePropertyList::unpack13(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + QueueProperty *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = QueueProperty::make_queue_of13_property(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->len(); + p += prop->len(); + } + return 0; +} + +QueuePropertyList& QueuePropertyList::operator=(QueuePropertyList other) { + swap(*this, other); + return *this; +} + +void swap(QueuePropertyList& first, QueuePropertyList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.property_list_, second.property_list_); +} + +void QueuePropertyList::add_property(QueueProperty *prop) { + this->property_list_.push_back(prop); + this->length_ += prop->len(); +} + +QueuePropRate::QueuePropRate() + : QueueProperty(), + rate_(0) { +} + +QueuePropRate::QueuePropRate(uint16_t property) + : QueueProperty(property), + rate_(0) { +} +; + +QueuePropRate::QueuePropRate(uint16_t property, uint16_t rate) + : QueueProperty(property), + rate_(rate) { +} + +bool QueuePropRate::equals(const QueueProperty &other) { + if (const QueuePropRate * prop = dynamic_cast(&other)) { + return ((QueueProperty::equals(other)) && (this->rate_ == prop->rate_)); + } + else { + return false; + } +} + +PacketQueueCommon::PacketQueueCommon() + : len_(0), + queue_id_(0), + properties_() { +} + +PacketQueueCommon::PacketQueueCommon(uint32_t queue_id) + : len_(0), + queue_id_(queue_id) { +} + +void PacketQueueCommon::property(QueuePropertyList properties) { + this->properties_ = properties; + this->len_ += properties.length(); +} + +bool PacketQueueCommon::operator==(const PacketQueueCommon &other) const { + return ((this->properties_ == other.properties_) + && (this->len_ == other.len_)); +} + +bool PacketQueueCommon::operator!=(const PacketQueueCommon &other) const { + return !(*this == other); +} + +void PacketQueueCommon::add_property(QueueProperty* qp) { + this->properties_.add_property(qp); + this->len_ += qp->len(); +} + +SwitchDesc::SwitchDesc(std::string mfr_desc, std::string hw_desc, + std::string sw_desc, std::string serial_num, std::string dp_desc) { + this->mfr_desc_ = mfr_desc; + this->hw_desc_ = hw_desc; + this->sw_desc_ = sw_desc; + this->serial_num_ = serial_num; + this->dp_desc_ = dp_desc; +} + +bool SwitchDesc::operator==(const SwitchDesc &other) const { + return ((this->mfr_desc_ == other.mfr_desc_) + && (this->hw_desc_ == other.hw_desc_) + && (this->sw_desc_ == other.sw_desc_) + && (this->serial_num_ == other.serial_num_) + && (this->dp_desc_ == other.dp_desc_)); +} + +bool SwitchDesc::operator!=(const SwitchDesc &other) const { + return !(*this == other); +} + +size_t SwitchDesc::pack(uint8_t* buffer) { + struct ofp_desc *ds = (struct ofp_desc *) buffer; + memset(ds->mfr_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->hw_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->sw_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->serial_num, 0x0, SERIAL_FLUID_NUM_LEN); + memset(ds->dp_desc, 0x0, DESC_FLUID_STR_LEN); + memcpy(ds->mfr_desc, this->mfr_desc_.c_str(), + this->mfr_desc_.size() < DESC_FLUID_STR_LEN ? + this->mfr_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->hw_desc, this->hw_desc_.c_str(), + this->hw_desc_.size() < DESC_FLUID_STR_LEN ? + this->hw_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->sw_desc, this->sw_desc_.c_str(), + this->sw_desc_.size() < DESC_FLUID_STR_LEN ? + this->sw_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->serial_num, this->serial_num_.c_str(), + this->serial_num_.size() < SERIAL_FLUID_NUM_LEN ? + this->serial_num_.size() : SERIAL_FLUID_NUM_LEN); + memcpy(ds->dp_desc, this->dp_desc_.c_str(), + this->dp_desc_.size() < DESC_FLUID_STR_LEN ? + this->dp_desc_.size() : DESC_FLUID_STR_LEN); + return 0; +} + +of_error SwitchDesc::unpack(uint8_t* buffer) { + struct ofp_desc *ds = (struct ofp_desc *) buffer; + this->mfr_desc_ = std::string(ds->mfr_desc); + this->hw_desc_ = std::string(ds->hw_desc); + this->sw_desc_ = std::string(ds->sw_desc); + this->serial_num_ = std::string(ds->serial_num); + this->dp_desc_ = std::string(ds->dp_desc); + + return 0; +} + +FlowStatsCommon::FlowStatsCommon() + : length_(0), + table_id_(0), + duration_sec_(0), + duration_nsec_(0), + priority_(0), + idle_timeout_(0), + hard_timeout_(0), + cookie_(0), + packet_count_(0), + byte_count_(0) { +} + +FlowStatsCommon::FlowStatsCommon(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count) + : length_(0), + table_id_(table_id), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + priority_(priority), + idle_timeout_(idle_timeout), + hard_timeout_(hard_timeout), + cookie_(cookie), + packet_count_(packet_count), + byte_count_(byte_count) { +} + +bool FlowStatsCommon::operator==(const FlowStatsCommon &other) const { + return ((this->table_id_ == other.table_id_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->priority_ == other.priority_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->cookie_ == other.cookie_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool FlowStatsCommon::operator!=(const FlowStatsCommon &other) const { + return !(*this == other); +} + +TableStatsCommon::TableStatsCommon() + : table_id_(0), + active_count_(0), + lookup_count_(0), + matched_count_(0) { +} + +TableStatsCommon::TableStatsCommon(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count) + : table_id_(table_id), + active_count_(active_count), + lookup_count_(lookup_count), + matched_count_(matched_count) { +} + +bool TableStatsCommon::operator==(const TableStatsCommon &other) const { + return ((this->table_id_ == other.table_id_) + && (this->active_count_ == other.active_count_) + && (this->lookup_count_ == other.lookup_count_) + && (this->matched_count_ == other.matched_count_)); +} + +bool TableStatsCommon::operator!=(const TableStatsCommon &other) const { + return !(*this == other); +} + +PortStatsCommon::PortStatsCommon() + : collisions_(0) { +} + +PortStatsCommon::PortStatsCommon(struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions) { + this->rx_tx_stats = rx_tx_stats; + this->err_stats = err_stats; + this->collisions_ = collisions; +} + +bool PortStatsCommon::operator==(const PortStatsCommon &other) const { + return ((this->rx_tx_stats == other.rx_tx_stats) + && (this->err_stats == other.err_stats) + && (this->collisions_ == other.collisions_)); +} + +bool PortStatsCommon::operator!=(const PortStatsCommon &other) const { + return !(*this == other); +} + +size_t PortStatsCommon::pack(uint8_t* buffer) { + struct port_rx_tx_stats *rt = (struct port_rx_tx_stats *) buffer; + struct port_err_stats *es = (struct port_err_stats *) (buffer + + sizeof(struct port_rx_tx_stats)); + rt->rx_packets = hton64(this->rx_tx_stats.rx_packets); + rt->tx_packets = hton64(this->rx_tx_stats.tx_packets); + rt->rx_bytes = hton64(this->rx_tx_stats.rx_bytes); + rt->tx_bytes = hton64(this->rx_tx_stats.tx_bytes); + rt->rx_dropped = hton64(this->rx_tx_stats.rx_dropped); + rt->tx_dropped = hton64(this->rx_tx_stats.tx_dropped); + es->rx_errors = hton64(this->err_stats.rx_errors); + es->tx_errors = hton64(this->err_stats.tx_errors); + es->rx_frame_err = hton64(this->err_stats.rx_frame_err); + es->rx_over_err = hton64(this->err_stats.rx_over_err); + es->rx_crc_err = hton64(this->err_stats.rx_crc_err); + return 0; +} + +of_error PortStatsCommon::unpack(uint8_t* buffer) { + struct port_rx_tx_stats *rt = (struct port_rx_tx_stats *) buffer; + struct port_err_stats *es = (struct port_err_stats *) (buffer + + sizeof(struct port_rx_tx_stats)); + this->rx_tx_stats.rx_packets = hton64(rt->rx_packets); + this->rx_tx_stats.tx_packets = hton64(rt->tx_packets); + this->rx_tx_stats.rx_bytes = hton64(rt->rx_bytes); + this->rx_tx_stats.tx_bytes = hton64(rt->tx_bytes); + this->rx_tx_stats.rx_dropped = hton64(rt->rx_dropped); + this->rx_tx_stats.tx_dropped = hton64(rt->tx_dropped); + this->err_stats.rx_errors = hton64(es->rx_errors); + this->err_stats.tx_errors = hton64(es->tx_errors); + this->err_stats.rx_frame_err = hton64(es->rx_frame_err); + this->err_stats.rx_over_err = hton64(es->rx_over_err); + this->err_stats.rx_crc_err = hton64(es->rx_crc_err); + return 0; +} + +QueueStatsCommon::QueueStatsCommon() + : queue_id_(0), + tx_bytes_(0), + tx_packets_(0), + tx_errors_(0) { +} + +QueueStatsCommon::QueueStatsCommon(uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors) + : queue_id_(queue_id), + tx_bytes_(tx_bytes), + tx_packets_(tx_packets), + tx_errors_(tx_errors) { +} + +bool QueueStatsCommon::operator==(const QueueStatsCommon &other) const { + return ((this->queue_id_ == other.queue_id_) + && (this->tx_bytes_ == other.tx_bytes_) + && (this->tx_packets_ == other.tx_packets_) + && (this->tx_errors_ == other.tx_errors_)); +} + +bool QueueStatsCommon::operator!=(const QueueStatsCommon &other) const { + return !(*this == other); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/ofcommon/msg.cc b/src/ovs/libfluid-msg/ofcommon/msg.cc new file mode 100644 index 00000000..a8d51c50 --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/msg.cc @@ -0,0 +1,479 @@ +#include "libfluid-msg/ofcommon/msg.hh" +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +/*OpenFlow message header class constructor*/ +OFMsg::OFMsg(uint8_t version, uint8_t type) + : version_(version), + type_(type), + length_(sizeof(struct ofp_fluid_header)), + xid_(0) { +} + +/*OpenFlow message header class constructor*/ +OFMsg::OFMsg(uint8_t version, uint8_t type, uint32_t xid) + : version_(version), + type_(type), + length_(sizeof(struct ofp_fluid_header)), + xid_(xid) { +} + +uint8_t* OFMsg::pack() { + uint8_t * buffer = new uint8_t[this->length_]; + memset(buffer, 0x0, this->length_); + struct ofp_fluid_header *oh = (struct ofp_fluid_header*) buffer; + oh->version = this->version_; + oh->type = this->type_; + oh->length = hton16(this->length_); + oh->xid = hton32(this->xid_); + return buffer; +} + +of_error OFMsg::unpack(uint8_t *buffer) { + struct ofp_fluid_header *oh = (struct ofp_fluid_header*) buffer; + this->version_ = oh->version; + this->type_ = oh->type; + this->length_ = ntoh16(oh->length); + this->xid_ = ntoh32(oh->xid); + return 0; +} + +bool OFMsg::operator==(const OFMsg &other) const { + return ((this->version_ == other.version_) && (this->type_ == other.type_) + && (this->length_ == other.length_) && (this->xid_ == other.xid_)); +} + +bool OFMsg::operator!=(const OFMsg &other) const { + return !(*this == other); +} + +EchoCommon::EchoCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0) { +} +uint8_t* EchoCommon::pack() { + uint8_t *buffer = OFMsg::pack(); + memcpy(buffer + sizeof(struct ofp_fluid_header), this->data_, this->data_len_); + return buffer; +} + +of_error EchoCommon::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + this->data_len_ = this->length_ - sizeof(struct ofp_fluid_header); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, buffer + sizeof(struct ofp_fluid_header), + this->data_len_); + } + else + this->data_ = NULL; + return 0; +} + +bool EchoCommon::operator==(const EchoCommon &other) const { + return ((OFMsg::operator==(other)) && (this->data_len_ == other.data_len_) + && (!memcmp(this->data_, other.data_, this->data_len_))); +} + +bool EchoCommon::operator!=(const EchoCommon &other) const { + return !(*this == other); +} + +void EchoCommon::data(void* data, size_t data_len) { + this->data_ = ::operator new(data_len); + memcpy(this->data_, data, data_len); + this->length_ += data_len; + this->data_len_ = data_len; +} + +EchoCommon::~EchoCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + err_type_(0), + code_(0) { +} +; + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t err_type, uint16_t code) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0) { + this->length_ = sizeof(struct ofp_fluid_error_msg); + this->err_type_ = err_type; + this->code_ = code; +} + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t err_type, uint16_t code, void* data, size_t data_len) + : OFMsg(version, type, xid) { + this->length_ = sizeof(struct ofp_fluid_error_msg) + + (data_len <= 64 ? data_len : 64); + this->err_type_ = err_type; + this->code_ = code; + this->data_len_ = data_len; + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, data, this->data_len_); + } + else + this->data_ = NULL; +} + +ErrorCommon::~ErrorCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +bool ErrorCommon::operator==(const ErrorCommon &other) const { + return ((OFMsg::operator==(other)) && (this->err_type_ == other.err_type_) + && (this->code_ == other.code_) && (this->data_len_ == other.data_len_) + && (!memcmp(this->data_, other.data_, this->data_len_))); +} + +bool ErrorCommon::operator!=(const ErrorCommon &other) const { + return !(*this == other); +} + +void ErrorCommon::data(void *data, size_t data_len) { + this->data_ = ::operator new(data_len); + memcpy(this->data_, data, data_len); + this->data_len_ = data_len <= 64 ? data_len : 64; + this->length_ += this->data_len_; +} + +uint8_t* ErrorCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_fluid_error_msg *err = (struct ofp_fluid_error_msg*) buffer; + err->type = hton16(this->err_type_); + err->code = hton16(this->code_); + memcpy(err->data, this->data_, this->data_len_); + return buffer; +} + +of_error ErrorCommon::unpack(uint8_t *buffer) { + struct ofp_fluid_error_msg *err = (struct ofp_fluid_error_msg*) buffer; + OFMsg::unpack(buffer); + this->data_len_ = this->length_ - sizeof(struct ofp_fluid_error_msg); + this->err_type_ = ntoh16(err->type); + this->code_ = ntoh16(err->code); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, buffer + sizeof(struct ofp_fluid_error_msg), + this->data_len_); + } + else + this->data_ = NULL; + return 0; +} + +FeaturesReplyCommon::FeaturesReplyCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + datapath_id_(0), + n_buffers_(0), + n_tables_(0), + capabilities_(0) { +} + +FeaturesReplyCommon::FeaturesReplyCommon(uint8_t version, uint8_t type, + uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, uint8_t n_tables, + uint32_t capabilities) + : OFMsg(version, type, xid), + datapath_id_(datapath_id), + n_buffers_(n_buffers), + n_tables_(n_tables), + capabilities_(capabilities) { +} + +bool FeaturesReplyCommon::operator==(const FeaturesReplyCommon &other) const { + return ((OFMsg::operator==(other)) + && (this->datapath_id_ == other.datapath_id_) + && (this->n_buffers_ == other.n_buffers_) + && (this->n_tables_ == other.n_tables_) + && (this->capabilities_ == other.capabilities_)); +} + +bool FeaturesReplyCommon::operator!=(const FeaturesReplyCommon &other) const { + return !(*this == other); +} + +SwitchConfigCommon::SwitchConfigCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + flags_(0x0), + miss_send_len_(0) { +} + +SwitchConfigCommon::SwitchConfigCommon(uint8_t version, uint8_t type, + uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : OFMsg(version, type, xid), + flags_(flags), + miss_send_len_(miss_send_len) { + this->length_ = sizeof(struct ofp_fluid_switch_config); +} + +bool SwitchConfigCommon::operator==(const SwitchConfigCommon &other) const { + return ((OFMsg::operator==(other)) && (this->flags_ == other.flags_) + && (this->miss_send_len_ == other.miss_send_len_)); +} + +bool SwitchConfigCommon::operator!=(const SwitchConfigCommon &other) const { + return !(*this == other); +} + +uint8_t* SwitchConfigCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_fluid_switch_config *conf = (struct ofp_fluid_switch_config*) buffer; + conf->flags = hton16(this->flags_); + conf->miss_send_len = hton16(this->miss_send_len_); + return buffer; +} + +of_error SwitchConfigCommon::unpack(uint8_t *buffer) { + struct ofp_fluid_switch_config *conf = (struct ofp_fluid_switch_config*) buffer; + OFMsg::unpack(buffer); + // if(this->length_ < sizeof(struct ofp_fluid_switch_config)){ + // return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + // } + this->flags_ = ntoh16(conf->flags); + this->miss_send_len_ = ntoh16(conf->miss_send_len); + return 0; +} + +FlowModCommon::FlowModCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + cookie_(0), + idle_timeout_(0), + hard_timeout_(0), + priority_(0), + buffer_id_(0), + flags_(0) { +} + +FlowModCommon::FlowModCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t cookie, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint16_t flags) + : OFMsg(version, type, xid), + cookie_(cookie), + idle_timeout_(idle_timeout), + hard_timeout_(hard_timeout), + priority_(priority), + buffer_id_(buffer_id), + flags_(flags) { +} + +bool FlowModCommon::operator==(const FlowModCommon &other) const { + return ((OFMsg::operator==(other)) && (this->cookie_ == other.cookie_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->priority_ == other.priority_) + && (this->buffer_id_ == other.buffer_id_) + && (this->flags_ == other.flags_)); +} + +bool FlowModCommon::operator!=(const FlowModCommon &other) const { + return !(*this == other); +} + +PacketOutCommon::PacketOutCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + buffer_id_(0), + actions_len_(0) { +} + +PacketOutCommon::PacketOutCommon(uint8_t version, uint16_t type, uint32_t xid, + uint32_t buffer_id) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0), + buffer_id_(buffer_id), + actions_len_(0) { +} + +PacketOutCommon::~PacketOutCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +bool PacketOutCommon::operator==(const PacketOutCommon &other) const { + return ((OFMsg::operator==(other)) && (this->buffer_id_ == other.buffer_id_) + && (this->actions_len_ == other.actions_len_) + && (this->actions_ == other.actions_) + && (!memcmp(this->data_, other.data_, this->data_len_)) + && (this->data_len_ == other.data_len_)); +} + +bool PacketOutCommon::operator!=(const PacketOutCommon &other) const { + return !(*this == other); +} + +void PacketOutCommon::actions(ActionList actions) { + this->actions_ = actions; + this->actions_len_ = actions.length(); + this->length_ += actions_len(); +} + +void PacketOutCommon::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); + this->actions_len_ += action.length(); +} + +void PacketOutCommon::add_action(Action *action) { + this->actions_.add_action(action); + this->length_ += action->length(); + this->actions_len_ += action->length(); +} + +void PacketOutCommon::data(void* data, size_t len) { + this->data_ = ::operator new(len); + memcpy(this->data_, data, len); + this->data_len_ = len; + this->length_ += len; +} + +PacketInCommon::PacketInCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + buffer_id_(0), + total_len_(0), + reason_(0) { +} + +PacketInCommon::PacketInCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t buffer_id, uint16_t total_len, uint8_t reason) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0), + buffer_id_(buffer_id), + total_len_(total_len), + reason_(reason) { +} + +bool PacketInCommon::operator==(const PacketInCommon &other) const { + return ((OFMsg::operator==(other)) && (this->buffer_id_ == other.buffer_id_) + && (this->total_len_ == other.total_len_) + && (this->reason_ == other.reason_) + && (!memcmp(this->data_, other.data_, this->data_len_)) + && (this->data_len_ == other.data_len_)); +} + +bool PacketInCommon::operator!=(const PacketInCommon &other) const { + return !(*this == other); +} + +void PacketInCommon::data(void* data, size_t len) { + this->data_ = ::operator new(len); + memcpy(this->data_, data, len); + this->length_ += len; + this->data_len_ = len; +} + +PacketInCommon::~PacketInCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +FlowRemovedCommon::FlowRemovedCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + cookie_(0), + priority_(0), + reason_(0), + duration_sec_(0), + duration_nsec_(0), + idle_timeout_(0), + packet_count_(0), + byte_count_(0) { +} + +FlowRemovedCommon::FlowRemovedCommon(uint8_t version, uint8_t type, + uint32_t xid, uint64_t cookie, uint16_t priority, uint8_t reason, + uint32_t duration_sec, uint32_t duration_nsec, uint16_t idle_timeout, + uint64_t packet_count, uint64_t byte_count) + : OFMsg(version, type, xid), + cookie_(cookie), + priority_(priority), + reason_(reason), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + idle_timeout_(idle_timeout), + packet_count_(packet_count), + byte_count_(byte_count) { +} + +bool FlowRemovedCommon::operator==(const FlowRemovedCommon &other) const { + return ((OFMsg::operator==(other)) && (this->cookie_ == other.cookie_) + && (this->priority_ == other.priority_) + && (this->reason_ == other.reason_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool FlowRemovedCommon::operator!=(const FlowRemovedCommon &other) const { + return !(*this == other); +} + +PortStatusCommon::PortStatusCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + reason_(0) { +} + +PortStatusCommon::PortStatusCommon(uint8_t version, uint8_t type, uint32_t xid, + uint8_t reason) + : OFMsg(version, type, xid), + reason_(reason) { +} + +bool PortStatusCommon::operator==(const PortStatusCommon &other) const { + return ((OFMsg::operator==(other)) && (this->reason_ == other.reason_)); +} + +bool PortStatusCommon::operator!=(const PortStatusCommon &other) const { + return !(*this == other); +} + +PortModCommon::PortModCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + config_(0), + mask_(0), + advertise_(0) { +} + +PortModCommon::PortModCommon(uint8_t version, uint8_t type, uint32_t xid, + EthAddress hw_addr, uint32_t config, uint32_t mask, uint32_t advertise) + : OFMsg(version, type, xid), + hw_addr_(hw_addr), + config_(config), + mask_(mask), + advertise_(advertise) { +} + +bool PortModCommon::operator==(const PortModCommon &other) const { + return ((OFMsg::operator==(other)) && (this->hw_addr_ == other.hw_addr_) + && (this->config_ == other.config_) && (this->mask_ == other.mask_) + && (this->advertise_ == other.advertise_)); +} + +bool PortModCommon::operator!=(const PortModCommon &other) const { + return !(*this == other); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/util/ethaddr.cc b/src/ovs/libfluid-msg/util/ethaddr.cc new file mode 100644 index 00000000..fa5ee6e3 --- /dev/null +++ b/src/ovs/libfluid-msg/util/ethaddr.cc @@ -0,0 +1,65 @@ +#include "libfluid-msg/util/ethaddr.hh" +#include + +namespace fluid_msg{ + +EthAddress::EthAddress():data(){ +} + +EthAddress::EthAddress(const char* address) { + std::string sadress(address); + memcpy(this->data, data_from_string(address), IFHWADDRLEN); +} + +EthAddress::EthAddress(const std::string &address) { + memcpy(this->data, data_from_string(address),IFHWADDRLEN); +} + +EthAddress::EthAddress(const uint8_t* data) { + memcpy(this->data, data, IFHWADDRLEN); +} + +EthAddress::EthAddress(const EthAddress &other) { + memcpy(this->data, other.data, IFHWADDRLEN); +} + +EthAddress& EthAddress::operator=(const EthAddress &other) { + if (this != &other) { + memcpy(this->data, other.data, IFHWADDRLEN); + } + return *this; +} + +bool EthAddress::operator==(const EthAddress &other) const { + return memcmp(other.data, this->data, IFHWADDRLEN) == 0; +} + +std::string EthAddress::to_string() const { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (int i = 0; i < IFHWADDRLEN; i++) { + ss << std::setw(2) << (int) data[i]; + if (i < IFHWADDRLEN - 1) + ss << ':'; + } + + return ss.str(); +} +void EthAddress::set_data(uint8_t* array){ + memcpy(this->data, array, IFHWADDRLEN); +} + +uint8_t* EthAddress::data_from_string(const std::string &address) { + static uint8_t data[6]; + char sc; + int byte; + std::stringstream ss(address); + ss << std::hex; + for (int i = 0; i < IFHWADDRLEN; i++) { + ss >> byte; + ss >> sc; + data[i] = (uint8_t) byte; + } + return data; +} +} diff --git a/src/ovs/libfluid-msg/util/ipaddr.cc b/src/ovs/libfluid-msg/util/ipaddr.cc new file mode 100644 index 00000000..38cfa5d8 --- /dev/null +++ b/src/ovs/libfluid-msg/util/ipaddr.cc @@ -0,0 +1,130 @@ +#include "libfluid-msg/util/ipaddr.hh" +#include +#include + +namespace fluid_msg{ + +IPAddress::IPAddress():version(NONE){ + memset(&ipv6, 0x0, 16); +} + +IPAddress::IPAddress(const char* address){ + std::string saddress(address); + if (saddress.find('.') != std::string::npos){ + this->version = IPV4; + this->ipv4 = IPv4from_string(address); + } + else if (saddress.find(':') != std::string::npos){ + this->version = IPV6; + struct in6_addr addr = IPv6from_string(address); + memcpy(this->ipv6, &addr, 16); + } +} + +IPAddress::IPAddress(const std::string &address){ + if (address.find('.') != std::string::npos){ + this->version = IPV4; + this->ipv4 = IPv4from_string(address); + } + else if (address.find(':') != std::string::npos){ + this->version = IPV6; + struct in6_addr addr = IPv6from_string(address); + memcpy(this->ipv6, &addr, 16); + } +} + +IPAddress::IPAddress(const IPAddress &other): version(other.version) { + if(this->version == IPV4){ + this->ipv4 = other.ipv4; + } + else { + memcpy(&this->ipv6, &other.ipv6, 16); + } +} + +IPAddress::IPAddress(const uint32_t ip_addr): version(IPV4), ipv4(ip_addr){ +} + +IPAddress::IPAddress(const uint8_t ip_addr[16]):version(IPV6){ + memcpy(this->ipv6, ip_addr, 16); +} + +IPAddress::IPAddress(const struct in_addr& ip_addr):version(IPV4), ipv4(ip_addr.s_addr) { +} + +IPAddress::IPAddress(const struct in6_addr& ip_addr):version(IPV6){ + memcpy(&ipv6, &ip_addr, sizeof(struct in6_addr)); +} + +IPAddress& IPAddress::operator=(const IPAddress &other) { + if (this != &other) { + this->version = other.version; + if(this->version == IPV4){ + this->ipv4 = other.ipv4; + } + else { + memcpy(&this->ipv6, &other.ipv6, 16); + } + } + return *this; +} + +bool IPAddress::operator==(const IPAddress &other) const { + if (this->version == IPV4 && other.version == IPV4){ + return (this->ipv4 == other.ipv4); + } + else { + if (this->version == IPV6 && other.version == IPV6){ + return memcmp(other.ipv6, &other.ipv6, 16); + } + } + return false; + +} + +int IPAddress::get_version() const { + return this->version; +} + +void IPAddress::setIPv4(uint32_t address){ + this->version = IPV4; + this->ipv4 = address; +} + +void IPAddress::setIPv6(uint8_t address[16]){ + this->version = IPV6; + memcpy(this->ipv6, address, 16); +} + +uint32_t IPAddress::getIPv4(){ + return this->ipv4; +} + +uint8_t* IPAddress::getIPv6(){ + return this->ipv6; +} + +uint32_t IPAddress::IPv4from_string(const std::string &address){ + struct in_addr n; + int pos = address.find('/'); + if (pos != std::string::npos){ + int prefix = atoi(address.substr(pos+1).c_str()); + std::string ip = address.substr(0, pos); + inet_pton(AF_INET, ip.c_str(), &n); + for(int i = prefix; i < 32; i++){ + n.s_addr &= ~(1 << i); + } + } + else{ + inet_pton(AF_INET, address.c_str(), &n); + } + return n.s_addr; +} + +struct in6_addr IPAddress::IPv6from_string(const std::string &address){ + struct in6_addr n6; + inet_pton(AF_INET6, address.c_str(), &n6); + return n6; +} + +} diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp new file mode 100644 index 00000000..c59add80 --- /dev/null +++ b/src/ovs/of_controller.cpp @@ -0,0 +1,166 @@ +#include + +#include "of_controller.h" +#include "aca_log.h" +#include "aca_util.h" + +using namespace fluid_base; +using namespace fluid_msg; + +void OFController::stop() { + switch_map_mutex.lock(); + + for (auto iter: switch_conn_map) { + // close all OFConnection + if (NULL != iter.second) { + iter.second->close(); + } + } + switch_conn_map.clear(); + switch_id_map.clear(); + + switch_map_mutex.unlock(); +} + +void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* data, size_t len) { + if (type == fluid_msg::of13::OFPT_FEATURES_REPLY) { + ACA_LOG_INFO("OFController::message_callback - ovs connection id=%d up\n", ofconn->get_id()); + + fluid_msg::of13::FeaturesReply reply; + auto err = reply.unpack((uint8_t *) data); + if (err != 0) { + ACA_LOG_ERROR("%s", "OFController::message_callback - failed to parse feature reply\n"); + return; + } else { + uint64_t dpid = reply.datapath_id(); + ACA_LOG_INFO("OFController::message_callback - ovs connection %d with dpid %ld\n", ofconn->get_id(), dpid); + + // parse which bridge is the connection from + std::string bridge_name = switch_dpid_map[dpid]; + add_switch_to_conn_map(bridge_name, ofconn->get_id(), ofconn); + } + } else if (type == fluid_msg::of13::OFPT_BARRIER_REPLY) { + auto t = std::chrono::high_resolution_clock::now(); + ACA_LOG_INFO("OFController::message_callback - recv OFPT_BARRIER_REPLY on %ld\n", t.time_since_epoch().count()); + } else if (type == 33) { // OFPRAW_OFPT14_BUNDLE_CONTROL + auto t = std::chrono::high_resolution_clock::now(); + + BundleReplyMessage bundle_reply; + bundle_reply.unpack(data); + ACA_LOG_INFO("OFController::message_callback - recv bundle_ctrl_reply of type %ld of bundle id %ld on %ld\n", + bundle_reply.get_type(), + bundle_reply.get_bundle_id(), + t.time_since_epoch().count()); + } +} + +void OFController::connection_callback(OFConnection* ofconn, OFConnection::Event type) { + if (type == OFConnection::EVENT_STARTED) { + ACA_LOG_INFO("OFController::connection_callback - ovs connection id=%d started\n", ofconn->get_id()); + } else if (type == OFConnection::EVENT_ESTABLISHED) { + ACA_LOG_INFO("OFController::connection_callback - ovs connection ver=%d id=%d established\n", ofconn->get_version(), ofconn->get_id()); + } else if (type == OFConnection::EVENT_FAILED_NEGOTIATION) { + ACA_LOG_ERROR("OFController::connection_callback - ovs connection id=%d failed version negotiation\n", ofconn->get_id()); + } else if (type == OFConnection::EVENT_CLOSED) { + std::string bridge = switch_id_map[ofconn->get_id()]; + ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed by user, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); + remove_switch_from_conn_map(ofconn->get_id()); + remove_switch_from_conn_map(bridge); + } else if (type == OFConnection::EVENT_DEAD) { + std::string bridge = switch_id_map[ofconn->get_id()]; + ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed due to inactivity, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); + remove_switch_from_conn_map(ofconn->get_id()); + remove_switch_from_conn_map(bridge); + } +} + +OFConnection* OFController::get_instance(std::string bridge) { + OFConnection* ofconn = NULL; + + switch_map_mutex.lock(); + ofconn = switch_conn_map[bridge]; + switch_map_mutex.unlock(); + + if (NULL == ofconn) { + ACA_LOG_ERROR("OFController::get_instance - switch %s not found\n", bridge.c_str()); + } + + return ofconn; +} + +void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn) { + switch_map_mutex.lock(); + if (switch_conn_map.find(bridge) != switch_conn_map.end()) { + // if existing already, remove then insert to update + remove_switch_from_conn_map(bridge); + } + switch_conn_map[bridge] = ofconn; + + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { + // if existing already, remove then insert to update + remove_switch_from_conn_map(ofconn_id); + } + switch_id_map[ofconn_id] = bridge; + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::add_switch_to_conn_map - ovs connection id=%d bridge=%s added to switch map\n", + ofconn->get_id(), bridge.c_str()); +} + +void OFController::remove_switch_from_conn_map(std::string bridge) { + switch_map_mutex.lock(); + auto ofconn_iter = switch_conn_map.find(bridge); + + // if found, remove + if (ofconn_iter != switch_conn_map.end()) { + if (NULL != ofconn_iter->second) { // k is bridge name, v is OFConnection* + ofconn_iter->second->close(); + } + switch_conn_map.erase(bridge); + } + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection bridge=%s removed from switch map\n", + bridge.c_str()); +} + +void OFController::remove_switch_from_conn_map(int ofconn_id) { + switch_map_mutex.lock(); + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { + switch_id_map.erase(ofconn_id); + } + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection id=%d removed from switch map\n", + ofconn_id); +} + +void OFController::send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p) { + p->set_xid(xid.fetch_add(1)); + auto buf = p->pack(); + + if (!buf) { + return; + } + + ofconn->send(buf->data(), buf->len()); +} + +void OFController::send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods) { + xid.fetch_add(1); + BundleFlowModMessage bundle(flow_mods, &xid); + auto buf_open_req = bundle.pack_open_req(); + ofconn->send(buf_open_req->data(), buf_open_req->len()); + ACA_LOG_INFO("OFController::send_bundle_flow_mods - ovs connection id=%d send bundle open request of bundle_id %ld\n", + ofconn->get_id(), bundle.get_bundle_id()); + + // handle flow-mods + for (auto flow_mod : bundle.pack_flow_mods()) { + ofconn->send(flow_mod->data(), flow_mod->len()); + } + + auto buf_commit_req = bundle.pack_commit_req(); + ofconn->send(buf_commit_req->data(), buf_commit_req->len()); + ACA_LOG_INFO("OFController::send_bundle_flow_mods - ovs connection id=%d send bundle commit request of bundle_id %ld\n", + ofconn->get_id(), bundle.get_bundle_id()); +} \ No newline at end of file diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp new file mode 100644 index 00000000..88745966 --- /dev/null +++ b/src/ovs/of_message.cpp @@ -0,0 +1,270 @@ +#include "of_message.h" +#include "aca_log.h" +#include "aca_util.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP + +#include +#include +#include +#include +#include +#include + +enum { + ADD_FLOW = 0, + MODIFY_FLOW = 1, + MODIFY_FLOW_STRICT = 2, + DELETE_FLOW = 3, + DELETE_FLOW_STRICT = 4, +}; + +template +struct FreeDeleter { + void operator()(T* p) const { + free(p); + } +}; +typedef std::unique_ptr> OFString; +typedef std::unique_ptr> OFPact; + +const ofputil_protocol DEFAULT_OF_VERSION = OFPUTIL_P_OF13_OXM; +const ofputil_protocol BUNDLE_OF_VERSION = OFPUTIL_P_OF14_OXM; + +class OFPBuf : public OFRawBuf { +public: + OFPBuf(ofpbuf* b) : _buf(b) {} + ~OFPBuf() override { + ofpbuf_delete(_buf); + _buf = nullptr; + } + void* data() override { + return _buf->data; + } + size_t len() override { + return _buf->size; + } + +private: + struct ofpbuf* _buf; +}; + +class OFBaseMessage : public OFMessage { +public: + OFBaseMessage() : _xid(0) {} + uint32_t xid() override { + return _xid; + } + void set_xid(uint32_t id) override { + _xid = id; + } + + std::shared_ptr pack_ofpbuf(struct ofpbuf* buf) { + auto header = static_cast(buf->data); + header->xid = htonl(_xid); + + ofpmsg_update_length(buf); + + return std::make_shared(buf); + } + virtual ~OFBaseMessage() = default; + +private: + uint32_t _xid; +}; + +class FlowModMessage : public OFBaseMessage { +public: + FlowModMessage(int op_type, const std::string& flow, bool bundle = false) : + _op_type(op_type), + _flow(flow) + { + if (bundle) { + _of_ver = BUNDLE_OF_VERSION; + } else { + _of_ver = DEFAULT_OF_VERSION; + } + } + + ~FlowModMessage() override = default; + + std::shared_ptr pack() override { + int command = OFPFC_ADD; + std::string cmd_str = "ADD"; + + switch (_op_type) { + case MODIFY_FLOW: + command = OFPFC_MODIFY; + cmd_str = "MOD"; + break; + + case MODIFY_FLOW_STRICT: + command = OFPFC_MODIFY_STRICT; + cmd_str = "MOD STRICT"; + break; + + case DELETE_FLOW: + command = OFPFC_DELETE; + cmd_str = "DELETE"; + break; + + case DELETE_FLOW_STRICT: + command = OFPFC_DELETE_STRICT; + cmd_str = "DELETE STRICT"; + break; + + case ADD_FLOW: + default: + /* the description is from ovs implementation + * If 'command' is given as -2, 'string' may begin with a command name ("add", "modify", "delete", "modify_strict", or "delete_strict"). + * A missing command is treated as "add". */ + // command = OFPFC_ADD; + command = -2; + cmd_str = "ADD"; + break; + } + + struct ofputil_flow_mod fm; + enum ofputil_protocol usable_protocols; + + OFString error(parse_ofp_flow_mod_str(&fm, _flow.c_str(), NULL, + command, &usable_protocols)); + if (error.get()) { + ACA_LOG_ERROR("OFMessage - failed to parse flow: %s, error: %s\n", + _flow.c_str(), error.get()); + return {}; + } + + OFString req_s(ofputil_protocols_to_string(_of_ver)); + OFString usable_s(ofputil_protocols_to_string(usable_protocols)); + if (!(_of_ver & usable_protocols)) { + ACA_LOG_ERROR("OFMessage - flow not supported by requested OF version %s, flow: %s, usable_protocols: %s\n", + req_s.get(), _flow.c_str(), usable_s.get()); + return {}; + } + + auto buf = ofputil_encode_flow_mod((const ofputil_flow_mod *)&fm, _of_ver); + if (buf == nullptr) { + ACA_LOG_ERROR("OFMessage - failed to encode flow_str: %s, OF version: %s, usable_protocols: %s\n", + _flow.c_str(), req_s.get(), usable_s.get()); + return {}; + } + + //ACA_LOG_INFO("encode flow_str: %s, command: %s, type: %d, usable_protocols: %s\n", + // _flow.c_str(), cmd_str.c_str(), (int)(static_cast(buf->data)->type), usable_s.get()); + + // free fm.ofpacts + //OFPact ofpacts(fm.ofpacts); + free(CONST_CAST(struct ofpact *, fm.ofpacts)); + + return pack_ofpbuf(buf); + } + +private: + int _op_type; + std::string _flow; + enum ofputil_protocol _of_ver; +}; + +std::shared_ptr BundleFlowModMessage::pack_open_req() { + struct ofputil_bundle_ctrl_msg bundle_ctrl; + // needs to handshake OFPBCT_OPEN_REQUEST first for ovs to get ready for the following bundle + bundle_ctrl.type = OFPBCT_OPEN_REQUEST; + + // OFPBF_ORDERED ensures flows get programmed in order + // OFPBF_ATOMIC means packet atomic - + // a given packet from an input port or packet-out request should either be processed with none or + // with all of the modifications having been applied + bundle_ctrl.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + auto buf = ofputil_encode_bundle_ctrl_request(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_ctrl); + ofpmsg_update_length(buf); + + // save bundle_id for later use + _bundle_id = bundle_ctrl.bundle_id; + + return std::make_shared(buf); +} + +std::shared_ptr BundleFlowModMessage::pack_commit_req() { + struct ofputil_bundle_ctrl_msg bundle_ctrl; + // bundle_id has to be consistent with open request + bundle_ctrl.bundle_id = _bundle_id; + // OFPBCT_OPEN_REQUEST or bundle flow-mod needs to be followed with an OFPBCT_COMMIT_REQUEST message, + // otherwise error OFPBFC_TIMEOUT will occur + bundle_ctrl.type = OFPBCT_COMMIT_REQUEST; + // flags need to be consistent too + bundle_ctrl.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + auto buf = ofputil_encode_bundle_ctrl_request(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_ctrl); + ofpmsg_update_length(buf); + + return std::make_shared(buf); +} + +std::vector > BundleFlowModMessage::pack_flow_mods() { + std::vector > ret_buf; + + for (auto of_msg : _flow_mods) { + struct ofputil_bundle_add_msg bundle_flow_mod; + // all flow_mod messages in this bundle share the same bundle id which is generated by ofputil_bundle_ctrl_msg + bundle_flow_mod.bundle_id = _bundle_id; + // by default keep flags consistent with BundleCtrlMessage + bundle_flow_mod.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + + // input is std::shared_ptr of_msg, but need to retrieve data from casting it to std::shared_ptr + auto fm_msg = std::static_pointer_cast(of_msg); + // each flow-mod has a unique xid + fm_msg->set_xid(_fm_xid->fetch_add(1)); + + auto fm_buf = fm_msg->pack(); + // ofputil_bundle_add_msg->msg is (ofpheader*) + bundle_flow_mod.msg = static_cast(fm_buf->data()); + + auto buf = ofputil_encode_bundle_add(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_flow_mod); + + ret_buf.emplace_back(std::make_shared(buf)); + } + + return ret_buf; +} + +void BundleReplyMessage::unpack(void* data) { + struct ofputil_bundle_ctrl_msg bundle_ctrl_reply; + ofputil_decode_bundle_ctrl((ofp_header *)data, &bundle_ctrl_reply); + + _type = bundle_ctrl_reply.type; + _bundle_id = bundle_ctrl_reply.bundle_id; +} + +ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle) { + return std::make_shared(ADD_FLOW, flow, bundle); +} + +ofmsg_ptr_t create_add_flow(const std::string& flow) { + return std::make_shared(ADD_FLOW, flow); +} + +ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict) { + int op_type = strict ? MODIFY_FLOW_STRICT : MODIFY_FLOW; + return std::make_shared(op_type, flow); +} + +ofmsg_ptr_t create_del_flow(const std::string& flow, bool strict) { + int op_type = strict ? DELETE_FLOW_STRICT : DELETE_FLOW; + return std::make_shared(op_type, flow); +} + +std::vector create_add_flows(const std::vector& flows) +{ + std::vector ret; + for (const auto &flow : flows) { + ret.emplace_back(std::make_shared(ADD_FLOW, flow)); + } + + return ret; +} diff --git a/src/ovs/ovs_control.cpp b/src/ovs/ovs_control.cpp index 26063f6b..a05fa595 100644 --- a/src/ovs/ovs_control.cpp +++ b/src/ovs/ovs_control.cpp @@ -33,10 +33,10 @@ #include #include #include -#include +//#include //#include +//#include #include -#include #include #include @@ -82,15 +82,15 @@ namespace ovs_control { OVS_Control &OVS_Control::get_instance() { - // Instance is destroyed when program exits. - // It is instantiated on first use. - static OVS_Control instance; + // Instance is destroyed when program exits. + // It is instantiated on first use. + static OVS_Control instance; - /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ - allowed_protocols = static_cast(OFPUTIL_P_ANY); - bundle = true; + /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ + allowed_protocols = static_cast(OFPUTIL_P_ANY); + bundle = true; - return instance; + return instance; } int OVS_Control::use_names; @@ -100,65 +100,66 @@ bool OVS_Control::bundle; void OVS_Control::monitor(const char *bridge, const char *opt) { - verbosity = 2; - use_names = -1; + verbosity = 2; + use_names = -1; - /* -P, --packet-in-format: Packet IN format to use in monitor and snoop + /* -P, --packet-in-format: Packet IN format to use in monitor and snoop * commands. Either one of NXPIF_* to force a particular packet_in format, or * -1 to let ovs-ofctl choose the default. */ - int preferred_packet_in_format = -1; + int preferred_packet_in_format = -1; - vconn *vconn; - enum ofputil_protocol usable_protocols = static_cast(OFPUTIL_P_ANY); - bool resume_continuations = false; + vconn *vconn; + enum ofputil_protocol usable_protocols = static_cast(OFPUTIL_P_ANY); + bool resume_continuations = false; - set_allowed_ofp_versions("OpenFlow13"); + set_allowed_ofp_versions("OpenFlow13"); - open_vconn(bridge, &vconn); + open_vconn(bridge, &vconn); - string option; - stringstream iss(opt); + string option; + stringstream iss(opt); - /* If the user wants the invalid_ttl_to_controller feature, limit the + /* If the user wants the invalid_ttl_to_controller feature, limit the * OpenFlow versions to those that support that feature. (Support in * OpenFlow 1.0 is an Open vSwitch extension.) */ - while (iss >> option) { - if (option.compare("invalid_ttl") == 0) { - uint32_t usable_versions = - ((1u << OFP10_VERSION) | (1u << OFP11_VERSION) | (1u << OFP12_VERSION)); - uint32_t allowed_versions = get_allowed_ofp_versions(); - if (!(allowed_versions & usable_versions)) { - struct ds versions = DS_EMPTY_INITIALIZER; - ofputil_format_version_bitmap_names(&versions, usable_versions); - // ovs_fatal(0, "invalid_ttl requires one of the OpenFlow " - // "versions %s but none is enabled (use -O)", - // ds_cstr(&versions)); - ACA_LOG_ERROR("invalid_ttl requires one of the OpenFlow " - "versions %s but none is enabled (use -O)\n", - ds_cstr(&versions)); - } - mask_allowed_ofp_versions(usable_versions); - break; + while (iss >> option) { + if (option.compare("invalid_ttl") == 0) { + uint32_t usable_versions = ((1u << OFP10_VERSION) | (1u << OFP11_VERSION) | + (1u << OFP12_VERSION)); + uint32_t allowed_versions = get_allowed_ofp_versions(); + if (!(allowed_versions & usable_versions)) { + struct ds versions = DS_EMPTY_INITIALIZER; + ofputil_format_version_bitmap_names(&versions, usable_versions); + // ovs_fatal(0, "invalid_ttl requires one of the OpenFlow " + // "versions %s but none is enabled (use -O)", + // ds_cstr(&versions)); + ACA_LOG_ERROR("invalid_ttl requires one of the OpenFlow " + "versions %s but none is enabled (use -O)\n", + ds_cstr(&versions)); + } + mask_allowed_ofp_versions(usable_versions); + break; + } } - } - iss.str(opt); - iss.clear(); + iss.str(opt); + iss.clear(); - while (iss >> option) { - if (isdigit(option[0])) { - struct ofputil_switch_config config; + while (iss >> option) { + if (isdigit(option[0])) { + struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - config.miss_send_len = atoi(option.c_str()); - set_switch_config(vconn, &config); - } else if (option.compare("invalid_ttl") == 0) { - monitor_set_invalid_ttl_to_controller(vconn); - } else if (option.compare(0, 6, "watch:") == 0) { - ofputil_flow_monitor_request fmr; - ofpbuf *msg; - char *error; + fetch_switch_config(vconn, &config); + config.miss_send_len = atoi(option.c_str()); + set_switch_config(vconn, &config); + } else if (option.compare("invalid_ttl") == 0) { + monitor_set_invalid_ttl_to_controller(vconn); + } else if (option.compare(0, 6, "watch:") == 0) { + ofputil_flow_monitor_request fmr; + ofpbuf *msg; + char *error; + /* inactive due to switching ovs dependency error = parse_flow_monitor_request(&fmr, option.substr(6).c_str(), ports_to_accept(bridge), tables_to_accept(bridge), &usable_protocols); @@ -176,514 +177,525 @@ void OVS_Control::monitor(const char *bridge, const char *opt) "the allowed flow formats (%s)", usable_s, allowed_s); } - - msg = ofpbuf_new(0); - ofputil_append_flow_monitor_request(&fmr, msg); - dump_transaction(vconn, msg, bridge); - fflush(stdout); - } else if (option.compare("resume") == 0) { - /* This option is intentionally undocumented because it is meant + */ + + msg = ofpbuf_new(0); + ofputil_append_flow_monitor_request(&fmr, msg); + dump_transaction(vconn, msg, bridge); + fflush(stdout); + } else if (option.compare("resume") == 0) { + /* This option is intentionally undocumented because it is meant * only for testing. */ - resume_continuations = true; - /* Set miss_send_len to ensure that we get packet-ins. */ - struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - config.miss_send_len = UINT16_MAX; - set_switch_config(vconn, &config); - } else { - //ovs_fatal(0, "%s: unsupported \"monitor\" argument", option); - ACA_LOG_ERROR("%s: unsupported monitor argument", option.c_str()); + resume_continuations = true; + /* Set miss_send_len to ensure that we get packet-ins. */ + struct ofputil_switch_config config; + fetch_switch_config(vconn, &config); + config.miss_send_len = UINT16_MAX; + set_switch_config(vconn, &config); + } else { + //ovs_fatal(0, "%s: unsupported \"monitor\" argument", option); + ACA_LOG_ERROR("%s: unsupported monitor argument", option.c_str()); + } } - } - if (preferred_packet_in_format >= 0) { - /* A particular packet-in format was requested, so we must set it. */ - set_packet_in_format( - vconn, static_cast(preferred_packet_in_format), true); - } else { - /* Otherwise, we always prefer NXT_PACKET_IN2. */ - if (!set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT2, false)) { - /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request + if (preferred_packet_in_format >= 0) { + /* A particular packet-in format was requested, so we must set it. */ + set_packet_in_format( + vconn, static_cast(preferred_packet_in_format), true); + } else { + /* Otherwise, we always prefer NXT_PACKET_IN2. */ + if (!set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN2, false)) { + /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request * NXT_PACKET_IN. (Before 2.6, Open vSwitch will accept a request * for NXT_PACKET_IN with OF1.1+, but even after that it still * sends packet-ins in the OpenFlow native format.) */ - if (vconn_get_version(vconn) == OFP10_VERSION) { - set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT, false); - } + if (vconn_get_version(vconn) == OFP10_VERSION) { + set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN, false); + } + } } - } - monitor_vconn(vconn, true, resume_continuations, bridge); + monitor_vconn(vconn, true, resume_continuations, bridge); } void OVS_Control::packet_out(const char *bridge, const char *options) { - enum ofputil_protocol usable_protocols; - enum ofputil_protocol protocol; - struct ofputil_packet_out po; - struct vconn *vconn; - struct ofpbuf *opo; - char *error; - - error = parse_ofp_packet_out_str(&po, options, ports_to_accept(bridge), - tables_to_accept(bridge), &usable_protocols); - if (error) { - //ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - } - protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); - opo = ofputil_encode_packet_out(&po, protocol); - transact_noreply(vconn, opo); - vconn_close(vconn); - free(CONST_CAST(void *, po.packet)); - free(po.ofpacts); + enum ofputil_protocol usable_protocols; + enum ofputil_protocol protocol; + struct ofputil_packet_out po; + struct vconn *vconn; + struct ofpbuf *opo; + char *error; + + error = parse_ofp_packet_out_str(&po, options, ports_to_accept(bridge), &usable_protocols); + if (error) { + //ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + } + protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); + opo = ofputil_encode_packet_out(&po, protocol); + transact_noreply(vconn, opo); + vconn_close(vconn); + free(CONST_CAST(void *, po.packet)); + free(po.ofpacts); } int OVS_Control::dump_flows(const char *bridge, const char *flow, bool show_stats) { - ACA_LOG_DEBUG("%s", "OVS_Control::dump_flows ---> Entering\n"); + ACA_LOG_DEBUG("%s", "OVS_Control::dump_flows ---> Entering\n"); - int rc = EXIT_FAILURE; - int n_criteria = 0; + int rc = EXIT_FAILURE; + int n_criteria = 0; - ACA_LOG_INFO("Executing dump_flows on bridge: %s, flow: %s, show_stats: %d\n", - bridge, flow, show_stats); + ACA_LOG_INFO("Executing dump_flows on bridge: %s, flow: %s, show_stats: %d\n", + bridge, flow, show_stats); - auto openflow_client_start = chrono::steady_clock::now(); + auto openflow_client_start = chrono::steady_clock::now(); - if (!n_criteria && !should_show_names() && show_stats) { - dump_flows__(bridge, flow, false); - rc = EXIT_SUCCESS; - } else { - ofputil_flow_stats_request fsr; - enum ofputil_protocol protocol; - struct vconn *vconn; + if (!n_criteria && !should_show_names() && show_stats) { + dump_flows__(bridge, flow, false); + rc = EXIT_SUCCESS; + } else { + ofputil_flow_stats_request fsr; + enum ofputil_protocol protocol; + struct vconn *vconn; + + vconn = prepare_dump_flows(bridge, flow, false, &fsr, &protocol); + struct ofputil_flow_stats *fses; + size_t n_fses; + run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses), "dump flows"); + + struct ds s = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < n_fses; i++) { + ds_clear(&s); + //ofputil_flow_stats_format(&s, &fses[i], ports_to_show(bridge), tables_to_show(bridge), + // //ports_to_show(ctx->argv[1]), + // //tables_to_show(ctx->argv[1]), + // show_stats); + //ACA_LOG_DEBUG(" %s\n", ds_cstr(&s)); + } + if (n_fses > 0) + rc = EXIT_SUCCESS; - vconn = prepare_dump_flows(bridge, flow, false, &fsr, &protocol); - struct ofputil_flow_stats *fses; - size_t n_fses; - run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses), "dump flows"); - - struct ds s = DS_EMPTY_INITIALIZER; - for (size_t i = 0; i < n_fses; i++) { - ds_clear(&s); - ofputil_flow_stats_format(&s, &fses[i], ports_to_show(bridge), tables_to_show(bridge), - //ports_to_show(ctx->argv[1]), - //tables_to_show(ctx->argv[1]), - show_stats); - ACA_LOG_DEBUG(" %s\n", ds_cstr(&s)); - } - if (n_fses > 0) - rc = EXIT_SUCCESS; + ds_destroy(&s); - ds_destroy(&s); + for (size_t i = 0; i < n_fses; i++) { + free(CONST_CAST(struct ofpact *, fses[i].ofpacts)); + } + free(fses); - for (size_t i = 0; i < n_fses; i++) { - free(CONST_CAST(struct ofpact *, fses[i].ofpacts)); + vconn_close(vconn); } - free(fses); - vconn_close(vconn); - } + auto openflow_client_end = chrono::steady_clock::now(); - auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); - auto openflow_client_time_total_time = - cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + g_total_execute_openflow_time += openflow_client_time_total_time; - g_total_execute_openflow_time += openflow_client_time_total_time; + ACA_LOG_INFO("Elapsed time for dump_flows call took: %ld microseconds or %ld milliseconds. rc: %d\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time), rc); - ACA_LOG_INFO("Elapsed time for dump_flows call took: %ld microseconds or %ld milliseconds. rc: %d\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time), rc); + ACA_LOG_DEBUG("OVS_Control::dump_flows <--- Exiting, rc = %d\n", rc); - ACA_LOG_DEBUG("OVS_Control::dump_flows <--- Exiting, rc = %d\n", rc); - - return rc; + return rc; } void OVS_Control::dump_flows__(const char *bridge, const char *flow, bool aggregate) { - struct ofputil_flow_stats_request fsr; - enum ofputil_protocol protocol; - struct vconn *vconn; + struct ofputil_flow_stats_request fsr; + enum ofputil_protocol protocol; + struct vconn *vconn; - vconn = prepare_dump_flows(bridge, flow, aggregate, &fsr, &protocol); - dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol), bridge); - vconn_close(vconn); + vconn = prepare_dump_flows(bridge, flow, aggregate, &fsr, &protocol); + dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol), bridge); + vconn_close(vconn); } vconn *OVS_Control::prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, ofputil_flow_stats_request *fsr, ofputil_protocol *protocolp) { - const char *vconn_name = bridge; - enum ofputil_protocol usable_protocols, protocol; - struct vconn *vconn; - char *error; - - // const char *match = argc > 2 ? argv[2] : ""; - const char *match = flow; - const struct ofputil_port_map *port_map = *match ? ports_to_accept(vconn_name) : NULL; - const struct ofputil_table_map *table_map = *match ? tables_to_accept(vconn_name) : NULL; - error = parse_ofp_flow_stats_request_str(fsr, aggregate, match, port_map, - table_map, &usable_protocols); - if (error) { - //ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - } + const char *vconn_name = bridge; + enum ofputil_protocol usable_protocols, protocol; + struct vconn *vconn; + char *error; + + // const char *match = argc > 2 ? argv[2] : ""; + const char *match = flow; + const struct ofputil_port_map *port_map = *match ? ports_to_accept(vconn_name) : NULL; + //const struct ofputil_table_map *table_map = *match ? tables_to_accept(vconn_name) : NULL; + error = parse_ofp_flow_stats_request_str(fsr, aggregate, match, port_map, &usable_protocols); + if (error) { + //ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + } - protocol = open_vconn(vconn_name, &vconn); - *protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); - return vconn; + protocol = open_vconn(vconn_name, &vconn); + *protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); + return vconn; } enum ofputil_protocol OVS_Control::set_protocol_for_flow_dump(vconn *vconn, ofputil_protocol cur_protocol, ofputil_protocol usable_protocols) { - char *usable_s; - int i; - - for (i = 0; i < (int)ofputil_n_flow_dump_protocols; i++) { - enum ofputil_protocol f = ofputil_flow_dump_protocols[i]; - if (f & usable_protocols & allowed_protocols && try_set_protocol(vconn, f, &cur_protocol)) { - return f; + char *usable_s; + int i; + + for (i = 0; i < (int)ofputil_n_flow_dump_protocols; i++) { + enum ofputil_protocol f = ofputil_flow_dump_protocols[i]; + if (f & usable_protocols & allowed_protocols && + try_set_protocol(vconn, f, &cur_protocol)) { + return f; + } } - } - usable_s = ofputil_protocols_to_string(usable_protocols); - if (usable_protocols & allowed_protocols) { - // ovs_fatal(0, "switch does not support any of the usable flow " - // "formats (%s)", usable_s); - ACA_LOG_ERROR("switch does not support any of the usable flow " - "formats (%s)", - usable_s); - } else { - char *allowed_s = ofputil_protocols_to_string(allowed_protocols); - // ovs_fatal(0, "none of the usable flow formats (%s) is among the " - // "allowed flow formats (%s)", usable_s, allowed_s); - ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " - "allowed flow formats (%s)", - usable_s, allowed_s); - } - return (ofputil_protocol)0; + usable_s = ofputil_protocols_to_string(usable_protocols); + if (usable_protocols & allowed_protocols) { + // ovs_fatal(0, "switch does not support any of the usable flow " + // "formats (%s)", usable_s); + ACA_LOG_ERROR("switch does not support any of the usable flow " + "formats (%s)", + usable_s); + } else { + char *allowed_s = ofputil_protocols_to_string(allowed_protocols); + // ovs_fatal(0, "none of the usable flow formats (%s) is among the " + // "allowed flow formats (%s)", usable_s, allowed_s); + ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " + "allowed flow formats (%s)", + usable_s, allowed_s); + } + return (ofputil_protocol)0; } int OVS_Control::add_flow(const char *bridge, const char *flow) { - return flow_mod(bridge, flow, OFPFC_ADD); + return flow_mod(bridge, flow, OFPFC_ADD); } int OVS_Control::mod_flows(const char *bridge, const char *flow, bool strict) { - return flow_mod(bridge, flow, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); + return flow_mod(bridge, flow, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); } int OVS_Control::del_flows(const char *bridge, const char *flow, bool strict) { - return flow_mod(bridge, flow, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); + return flow_mod(bridge, flow, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); } int OVS_Control::flow_mod(const char *bridge, const char *flow, unsigned short int command) { - ACA_LOG_DEBUG("%s", "OVS_Control::flow_mod ---> Entering\n"); - - struct ofputil_flow_mod fm; - char *error; - enum ofputil_protocol usable_protocols; - int rc; - - ACA_LOG_INFO("Executing flow_mod on bridge: %s, flow: %s, command: %d\n", - bridge, flow, command); - - auto openflow_client_start = chrono::steady_clock::now(); - error = parse_ofp_flow_mod_str(&fm, flow, ports_to_accept(bridge), - tables_to_accept(bridge), command, &usable_protocols); - if (error) { - // ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - rc = EXIT_FAILURE; - } else { - // flow_mod__ returns void - std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); - - flow_mod__(bridge, &fm, 1, usable_protocols); - std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); - auto message_total_operation_time = - std::chrono::duration_cast(end - start).count(); - ACA_LOG_DEBUG("[flow_mod] Start flow_mod__ at: [%ld], finished at: [%ld]\nElapsed time for flow_mod__ took: %ld microseconds or %ld milliseconds\n", - start, end, message_total_operation_time, - (message_total_operation_time / 1000)); - rc = EXIT_SUCCESS; - } + ACA_LOG_DEBUG("%s", "OVS_Control::flow_mod ---> Entering\n"); + + struct ofputil_flow_mod fm; + char *error; + enum ofputil_protocol usable_protocols; + int rc; - auto openflow_client_end = chrono::steady_clock::now(); + ACA_LOG_INFO("Executing flow_mod on bridge: %s, flow: %s, command: %d\n", + bridge, flow, command); - auto openflow_client_time_total_time = - cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + auto openflow_client_start = chrono::steady_clock::now(); - g_total_execute_openflow_time += openflow_client_time_total_time; + error = parse_ofp_flow_mod_str(&fm, flow, ports_to_accept(bridge), command, &usable_protocols); + if (error) { + // ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + rc = EXIT_FAILURE; + } else { + // flow_mod__ returns void + std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); + + flow_mod__(bridge, &fm, 1, usable_protocols); + std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); + auto message_total_operation_time = + std::chrono::duration_cast(end - start).count(); + ACA_LOG_DEBUG("[flow_mod] Start flow_mod__ at: [%ld], finished at: [%ld]\nElapsed time for flow_mod__ took: %ld microseconds or %ld milliseconds\n", + start, end, message_total_operation_time, + (message_total_operation_time / 1000)); + rc = EXIT_SUCCESS; + } - ACA_LOG_INFO("Elapsed time for flow_mod call took: %ld microseconds or %ld milliseconds. rc: %d\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time), rc); + auto openflow_client_end = chrono::steady_clock::now(); - ACA_LOG_DEBUG("OVS_Control::flow_mod <--- Exiting, rc = %d\n", rc); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); - return rc; + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for flow_mod call took: %ld microseconds or %ld milliseconds. rc: %d\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time), rc); + + ACA_LOG_DEBUG("OVS_Control::flow_mod <--- Exiting, rc = %d\n", rc); + + return rc; } void OVS_Control::flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol protocol; - struct vconn *vconn; - size_t i; + enum ofputil_protocol protocol; + struct vconn *vconn; + size_t i; - if (bundle) { - bundle_flow_mod__(remote, fms, n_fms, usable_protocols); - return; - } + if (bundle) { + bundle_flow_mod__(remote, fms, n_fms, usable_protocols); + return; + } - protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); - for (i = 0; i < n_fms; i++) { - struct ofputil_flow_mod *fm = &fms[i]; + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; - transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); - free(CONST_CAST(struct ofpact *, fm->ofpacts)); - minimatch_destroy(&fm->match); - } - vconn_close(vconn); + transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + //free(&fm->match); + } + vconn_close(vconn); } void OVS_Control::bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol protocol; - struct vconn *vconn; - struct ovs_list requests; - size_t i; + enum ofputil_protocol protocol; + struct vconn *vconn; + char *usable_s; + struct ovs_list requests; + size_t i; - ovs_list_init(&requests); + ovs_list_init(&requests); - /* Bundles need OpenFlow 1.3+. */ - // usable_protocols &= OFPUTIL_P_OF13_UP; - protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + /* Bundles need OpenFlow 1.3+. */ + // usable_protocols &= OFPUTIL_P_OF13_UP; + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + usable_s = ofputil_protocols_to_string(protocol); + ACA_LOG_INFO("vconn uses ofp protocol (%s)\n", + usable_s); - for (i = 0; i < n_fms; i++) { - struct ofputil_flow_mod *fm = &fms[i]; - struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol); + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; + struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol); - ovs_list_push_back(&requests, &request->list_node); - free(CONST_CAST(struct ofpact *, fm->ofpacts)); - minimatch_destroy(&fm->match); - } + ovs_list_push_back(&requests, &request->list_node); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + //free(&fm->match); + } - bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); - ofpbuf_list_delete(&requests); - vconn_close(vconn); + bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); + ofpbuf_list_delete(&requests); + vconn_close(vconn); } enum ofputil_protocol OVS_Control::open_vconn_for_flow_mod(const char *remote, vconn **vconnp, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol cur_protocol; - char *usable_s; - int i; + enum ofputil_protocol cur_protocol; + char *usable_s; + int i; - if (!(usable_protocols & allowed_protocols)) { - char *allowed_s = ofputil_protocols_to_string(allowed_protocols); - usable_s = ofputil_protocols_to_string(usable_protocols); - // ovs_fatal(0, "none of the usable flow formats (%s) is among the " - // "allowed flow formats (%s)", usable_s, allowed_s); - ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " - "allowed flow formats (%s)", - usable_s, allowed_s); - } + if (!(usable_protocols & allowed_protocols)) { + char *allowed_s = ofputil_protocols_to_string(allowed_protocols); + usable_s = ofputil_protocols_to_string(usable_protocols); + // ovs_fatal(0, "none of the usable flow formats (%s) is among the " + // "allowed flow formats (%s)", usable_s, allowed_s); + ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " + "allowed flow formats (%s)", + usable_s, allowed_s); + } - /* If the initial flow format is allowed and usable, keep it. */ - cur_protocol = open_vconn(remote, vconnp); - if (usable_protocols & allowed_protocols & cur_protocol) { - return cur_protocol; - } + /* If the initial flow format is allowed and usable, keep it. */ + cur_protocol = open_vconn(remote, vconnp); + if (usable_protocols & allowed_protocols & cur_protocol) { + return cur_protocol; + } - /* Otherwise try each flow format in turn. */ - for (i = 0; i < (int)sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { - enum ofputil_protocol f = (ofputil_protocol)(1 << i); + /* Otherwise try each flow format in turn. */ + for (i = 0; i < (int)sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { + enum ofputil_protocol f = (ofputil_protocol)(1 << i); - if (f != cur_protocol && f & usable_protocols & allowed_protocols && - try_set_protocol(*vconnp, f, &cur_protocol)) { - return f; + if (f != cur_protocol && f & usable_protocols & allowed_protocols && + try_set_protocol(*vconnp, f, &cur_protocol)) { + return f; + } } - } - usable_s = ofputil_protocols_to_string(usable_protocols); - // ovs_fatal(0, "switch does not support any of the usable flow " - // "formats (%s)", usable_s); - ACA_LOG_ERROR("switch does not support any of the usable flow " - "formats (%s)", - usable_s); - return (ofputil_protocol)0; + usable_s = ofputil_protocols_to_string(usable_protocols); + // ovs_fatal(0, "switch does not support any of the usable flow " + // "formats (%s)", usable_s); + ACA_LOG_ERROR("switch does not support any of the usable flow " + "formats (%s)", + usable_s); + return (ofputil_protocol)0; } /* Returns the port number corresponding to 'port_name' (which may be a port * name or number) within the switch 'vconn_name'. */ ofp_port_t OVS_Control::str_to_port_no(const char *vconn_name, const char *port_name) { - ofp_port_t port_no; - if (ofputil_port_from_string(port_name, NULL, &port_no) || - ofputil_port_from_string(port_name, ports_to_accept(vconn_name), &port_no)) { - return port_no; - } - // ovs_fatal(0, "%s: unknown port `%s'", vconn_name, port_name); - ACA_LOG_ERROR("%s: unknown port `%s'", vconn_name, port_name); - return (ofputil_protocol)0; + ofp_port_t port_no; + if (ofputil_port_from_string(port_name, NULL, &port_no) || + ofputil_port_from_string(port_name, ports_to_accept(vconn_name), &port_no)) { + return port_no; + } + // ovs_fatal(0, "%s: unknown port `%s'", vconn_name, port_name); + ACA_LOG_ERROR("%s: unknown port `%s'", vconn_name, port_name); + return (ofputil_protocol)0; } bool OVS_Control::try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, enum ofputil_protocol *cur) { - for (;;) { - struct ofpbuf *request, *reply; - enum ofputil_protocol next; + for (;;) { + struct ofpbuf *request, *reply; + enum ofputil_protocol next; - request = ofputil_encode_set_protocol(*cur, want, &next); - if (!request) { - return *cur == want; - } + request = ofputil_encode_set_protocol(*cur, want, &next); + if (!request) { + return *cur == want; + } - run(vconn_transact_noreply(vconn, request, &reply), "talking to %s", - vconn_get_name(vconn)); - if (reply) { - char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2); - VLOG_DBG("%s: failed to set protocol, switch replied: %s", vconn_get_name(vconn), s); - free(s); - ofpbuf_delete(reply); - return false; - } + run(vconn_transact_noreply(vconn, request, &reply), "talking to %s", + vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, NULL, 2); + VLOG_DBG("%s: failed to set protocol, switch replied: %s", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + return false; + } - *cur = next; - } + *cur = next; + } } void OVS_Control::fetch_switch_config(vconn *vconn, ofputil_switch_config *config) { - struct ofpbuf *request; - struct ofpbuf *reply; - enum ofptype type; + struct ofpbuf *request; + struct ofpbuf *reply; + enum ofptype type; - request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, vconn_get_version(vconn), 0); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); + request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, vconn_get_version(vconn), 0); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); - if (ofptype_decode(&type, (ofp_header *)reply->data) || type != OFPTYPE_GET_CONFIG_REPLY) { - // ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn)); - ACA_LOG_ERROR("%s: bad reply to config request", vconn_get_name(vconn)); - } - ofputil_decode_get_config_reply((ofp_header *)reply->data, config); - ofpbuf_delete(reply); + if (ofptype_decode(&type, (ofp_header *)reply->data) || type != OFPTYPE_GET_CONFIG_REPLY) { + // ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn)); + ACA_LOG_ERROR("%s: bad reply to config request", vconn_get_name(vconn)); + } + ofputil_decode_get_config_reply((ofp_header *)reply->data, config); + ofpbuf_delete(reply); } void OVS_Control::set_switch_config(vconn *vconn, const ofputil_switch_config *config) { - ofp_version version = static_cast(vconn_get_version(vconn)); - transact_noreply(vconn, ofputil_encode_set_config(config, version)); + ofp_version version = static_cast(vconn_get_version(vconn)); + transact_noreply(vconn, ofputil_encode_set_config(config, version)); } int OVS_Control::open_vconn_socket(const char *name, vconn **vconnp) { - char vconn_name[50]; - int error; - - sprintf(vconn_name, "unix:%s", name); - error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp); - if (error && error != ENOENT) { - // ovs_fatal(0, "%s: failed to open socket (%s)", name, - // ovs_strerror(error)); - ACA_LOG_ERROR("%s: failed to open socket (%s)", name, ovs_strerror(error)); - } - // free(vconn_name); - return error; + char vconn_name[50]; + int error; + + sprintf(vconn_name, "unix:%s", name); + error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp); + if (error && error != ENOENT) { + // ovs_fatal(0, "%s: failed to open socket (%s)", name, + // ovs_strerror(error)); + ACA_LOG_ERROR("%s: failed to open socket (%s)", name, ovs_strerror(error)); + } + // free(vconn_name); + return error; } enum ofputil_protocol OVS_Control::open_vconn(const char *name, vconn **vconnp) { - const char *suffix = "mgmt"; - char *datapath_name, *datapath_type; - enum ofputil_protocol protocol; - char bridge_path[50] = "", socket_name[50] = ""; - int version; - int error; - - sprintf(bridge_path, "%s/%s.%s", ovs_rundir(), name, suffix); - dp_parse_name(name, &datapath_name, &datapath_type); - sprintf(socket_name, "%s/%s.%s", ovs_rundir(), datapath_name, suffix); - free(datapath_name); - free(datapath_type); - if (strchr(name, ':')) { - run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp), - "connecting to %s", name); - } else if (!open_vconn_socket(name, vconnp)) { - /* Fall Through. */ - } else if (!open_vconn_socket(bridge_path, vconnp)) { - /* Fall Through. */ - } else if (!open_vconn_socket(socket_name, vconnp)) { - /* Fall Through. */ - } else { - // free(bridge_path); - // free(socket_name); - // ovs_fatal(0, "%s is not a bridge or a socket", name); - ACA_LOG_ERROR("%s is not a bridge or a socket", name); - } + const char *suffix = "mgmt"; + char *datapath_name, *datapath_type; + enum ofputil_protocol protocol; + char bridge_path[50] = "", socket_name[50] = ""; + int version; + int error; + + // ovs_rundir() returns "/usr/local/var/run/openvswitch/", on some machine's ovs version it is not applicable + //sprintf(bridge_path, "%s/%s.%s", ovs_rundir(), name, suffix); + sprintf(bridge_path, "%s/%s.%s", "/var/run/openvswitch/", name, suffix); + ACA_LOG_INFO("bridge path is %s\n", bridge_path); + dp_parse_name(name, &datapath_name, &datapath_type); + //sprintf(socket_name, "%s/%s.%s", ovs_rundir(), datapath_name, suffix); + sprintf(socket_name, "%s/%s.%s", "/var/run/openvswitch/", datapath_name, suffix); + ACA_LOG_INFO("socket name is %s\n", socket_name); + free(datapath_name); + free(datapath_type); + + if (strchr(name, ':')) { + run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp), + "connecting to %s\n", name); + } else if (!open_vconn_socket(name, vconnp)) { + // Fall Through. + } else if (!open_vconn_socket(bridge_path, vconnp)) { + // Fall Through. + } else if (!open_vconn_socket(socket_name, vconnp)) { + // Fall Through. + } else { + // free(bridge_path); + // free(socket_name); + // ovs_fatal(0, "%s is not a bridge or a socket", name); + ACA_LOG_ERROR("%s is not a bridge or a socket", name); + } - // if (target == SNOOP) { - // vconn_set_recv_any_version(*vconnp); - // } + // if (target == SNOOP) { + // vconn_set_recv_any_version(*vconnp); + // } - // free(bridge_path); - // free(socket_name); + // free(bridge_path); + // free(socket_name); - VLOG_DBG("connecting to %s", vconn_get_name(*vconnp)); - error = vconn_connect_block(*vconnp, -1); - if (error) { - // ovs_fatal(0, "%s: failed to connect to socket (%s)", name, - // ovs_strerror(error)); - ACA_LOG_ERROR("%s: failed to connect to socket (%s)", name, ovs_strerror(error)); - } + ACA_LOG_INFO("connecting to %s\n", vconn_get_name(*vconnp)); + error = vconn_connect_block(*vconnp); + if (error) { + // ovs_fatal(0, "%s: failed to connect to socket (%s)", name, + // ovs_strerror(error)); + ACA_LOG_ERROR("%s: failed to connect to socket (%s)", name, ovs_strerror(error)); + } - version = vconn_get_version(*vconnp); - protocol = ofputil_protocol_from_ofp_version(static_cast(version)); - if (!protocol) { - // ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x", - // name, version); - ACA_LOG_ERROR("%s: unsupported OpenFlow version 0x%02x", name, version); - } - return protocol; + version = vconn_get_version(*vconnp); + protocol = ofputil_protocol_from_ofp_version(static_cast(version)); + if (!protocol) { + // ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x", + // name, version); + ACA_LOG_ERROR("%s: unsupported OpenFlow version 0x%02x", name, version); + } + return protocol; } int OVS_Control::monitor_set_invalid_ttl_to_controller(vconn *vconn) { - struct ofputil_switch_config config; + struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - if (!config.invalid_ttl_to_controller) { - config.invalid_ttl_to_controller = 1; - set_switch_config(vconn, &config); + fetch_switch_config(vconn, &config); + if (!config.invalid_ttl_to_controller) { + config.invalid_ttl_to_controller = 1; + set_switch_config(vconn, &config); - /* Then retrieve the configuration to see if it really took. OpenFlow + /* Then retrieve the configuration to see if it really took. OpenFlow * has ill-defined error reporting for bad flags, so this is about the * best we can do. */ - fetch_switch_config(vconn, &config); - if (!config.invalid_ttl_to_controller) { - // ovs_fatal(0, "setting invalid_ttl_to_controller failed (this " - // "switch probably doesn't support this flag)"); - ACA_LOG_ERROR("%s", "setting invalid_ttl_to_controller failed (this " - "switch probably doesn't support this flag)"); + fetch_switch_config(vconn, &config); + if (!config.invalid_ttl_to_controller) { + // ovs_fatal(0, "setting invalid_ttl_to_controller failed (this " + // "switch probably doesn't support this flag)"); + ACA_LOG_ERROR("%s", "setting invalid_ttl_to_controller failed (this " + "switch probably doesn't support this flag)"); + } } - } - return 0; + return 0; } /* Converts hex digits in 'hex' to an OpenFlow message in '*msgp'. The @@ -691,30 +703,30 @@ int OVS_Control::monitor_set_invalid_ttl_to_controller(vconn *vconn) * an error message and stores NULL in '*msgp'. */ const char *OVS_Control::openflow_from_hex(const char *hex, ofpbuf **msgp) { - struct ofp_header *oh; - struct ofpbuf *msg; + struct ofp_header *oh; + struct ofpbuf *msg; - msg = ofpbuf_new(strlen(hex) / 2); - *msgp = NULL; + msg = ofpbuf_new(strlen(hex) / 2); + *msgp = NULL; - if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') { - ofpbuf_delete(msg); - return "Trailing garbage in hex data"; - } + if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') { + ofpbuf_delete(msg); + return "Trailing garbage in hex data"; + } - if (msg->size < sizeof(struct ofp_header)) { - ofpbuf_delete(msg); - return "Message too short for OpenFlow"; - } + if (msg->size < sizeof(struct ofp_header)) { + ofpbuf_delete(msg); + return "Message too short for OpenFlow"; + } - oh = (ofp_header *)msg->data; - if (msg->size != ntohs(oh->length)) { - ofpbuf_delete(msg); - return "Message size does not match length in OpenFlow header"; - } + oh = (ofp_header *)msg->data; + if (msg->size != ntohs(oh->length)) { + ofpbuf_delete(msg); + return "Message size does not match length in OpenFlow header"; + } - *msgp = msg; - return NULL; + *msgp = msg; + return NULL; } /* Prints to stderr all of the messages received on 'vconn'. @@ -727,426 +739,422 @@ const char *OVS_Control::openflow_from_hex(const char *hex, ofpbuf **msgp) void OVS_Control::monitor_vconn(vconn *vconn, bool reply_to_echo_requests, bool resume_continuations, const char *bridge_) { - static const char *bridge = bridge_; - bool timestamp = true; - struct barrier_aux barrier_aux = { vconn, NULL }; - struct unixctl_server *server; - bool exiting = false; - bool blocked = false; - int error; - - // Put all functions used by daemon in a local struct. - struct X { - static void ofctl_exit(unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) - { - bool *exiting = (bool *)exiting_; - *exiting = true; - unixctl_command_reply(conn, NULL); - } - - static void ofctl_send(unixctl_conn *conn, int argc, const char *argv[], void *vconn_) - { - struct vconn *vconn = (struct vconn *)vconn_; - struct ds reply; - bool ok; - int i; - - ok = true; - ds_init(&reply); - for (i = 1; i < argc; i++) { - const char *error_msg; - struct ofpbuf *msg; - int error; - - error_msg = OVS_Control().openflow_from_hex(argv[i], &msg); - if (error_msg) { - ds_put_format(&reply, "%s\n", error_msg); - ok = false; - continue; + static const char *bridge = bridge_; + bool timestamp = true; + struct barrier_aux barrier_aux = { vconn, NULL }; + struct unixctl_server *server; + bool exiting = false; + bool blocked = false; + int error; + + // Put all functions used by daemon in a local struct. + struct X { + static void ofctl_exit(unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *exiting_) + { + bool *exiting = (bool *)exiting_; + *exiting = true; + unixctl_command_reply(conn, NULL); } - fprintf(stderr, "send: "); - ofp_print(stderr, msg->data, msg->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity); - OVS_Control().ports_to_show(bridge), - OVS_Control().tables_to_show(bridge), verbosity); - error = vconn_send_block(vconn, msg); - if (error) { - ofpbuf_delete(msg); - ds_put_format(&reply, "%s\n", ovs_strerror(error)); - ok = false; - } else { - ds_put_cstr(&reply, "sent\n"); + static void ofctl_send(unixctl_conn *conn, int argc, const char *argv[], void *vconn_) + { + struct vconn *vconn = (struct vconn *)vconn_; + struct ds reply; + bool ok; + int i; + + ok = true; + ds_init(&reply); + for (i = 1; i < argc; i++) { + const char *error_msg; + struct ofpbuf *msg; + int error; + + error_msg = OVS_Control().openflow_from_hex(argv[i], &msg); + if (error_msg) { + ds_put_format(&reply, "%s\n", error_msg); + ok = false; + continue; + } + + fprintf(stderr, "send: "); + ofp_print(stderr, msg->data, msg->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity); + OVS_Control().ports_to_show(bridge), verbosity); + error = vconn_send_block(vconn, msg); + if (error) { + ofpbuf_delete(msg); + ds_put_format(&reply, "%s\n", ovs_strerror(error)); + ok = false; + } else { + ds_put_cstr(&reply, "sent\n"); + } + } + + if (ok) { + unixctl_command_reply(conn, ds_cstr(&reply)); + } else { + unixctl_command_reply_error(conn, ds_cstr(&reply)); + } + ds_destroy(&reply); } - } - if (ok) { - unixctl_command_reply(conn, ds_cstr(&reply)); - } else { - unixctl_command_reply_error(conn, ds_cstr(&reply)); - } - ds_destroy(&reply); - } + static void unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc, + const char *argv[], void *vconn_) + { + struct vconn *vconn = (struct vconn *)vconn_; + enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version( + static_cast(vconn_get_version(vconn))); + struct ds reply = DS_EMPTY_INITIALIZER; + bool ok = true; + + enum ofputil_protocol usable_protocols; + struct ofputil_packet_out po; + char *error_msg; + + error_msg = parse_ofp_packet_out_str( + &po, argv[1], + // ports_to_accept(vconn_get_name(vconn)), + // tables_to_accept(vconn_get_name(vconn)), + OVS_Control().ports_to_accept(bridge), &usable_protocols); + if (error_msg) { + ds_put_format(&reply, "%s\n", error_msg); + free(error_msg); + ok = false; + } - static void unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc, - const char *argv[], void *vconn_) - { - struct vconn *vconn = (struct vconn *)vconn_; - enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version( - static_cast(vconn_get_version(vconn))); - struct ds reply = DS_EMPTY_INITIALIZER; - bool ok = true; - - enum ofputil_protocol usable_protocols; - struct ofputil_packet_out po; - char *error_msg; - - error_msg = parse_ofp_packet_out_str(&po, argv[1], - // ports_to_accept(vconn_get_name(vconn)), - // tables_to_accept(vconn_get_name(vconn)), - OVS_Control().ports_to_accept(bridge), - OVS_Control().tables_to_accept(bridge), - &usable_protocols); - if (error_msg) { - ds_put_format(&reply, "%s\n", error_msg); - free(error_msg); - ok = false; - } + if (ok && !(usable_protocols & protocol)) { + ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n"); + ok = false; + } - if (ok && !(usable_protocols & protocol)) { - ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n"); - ok = false; - } + if (ok) { + struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol); + + ofp_print(stderr, msg->data, msg->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity); + OVS_Control().ports_to_show(bridge), verbosity); + int error = vconn_send_block(vconn, msg); + if (error) { + ofpbuf_delete(msg); + ds_put_format(&reply, "%s\n", ovs_strerror(error)); + ok = false; + } + } + + if (ok) { + unixctl_command_reply(conn, ds_cstr(&reply)); + } else { + unixctl_command_reply_error(conn, ds_cstr(&reply)); + } + ds_destroy(&reply); - if (ok) { - struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol); - - ofp_print(stderr, msg->data, msg->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity); - OVS_Control().ports_to_show(bridge), - OVS_Control().tables_to_show(bridge), verbosity); - int error = vconn_send_block(vconn, msg); - if (error) { - ofpbuf_delete(msg); - ds_put_format(&reply, "%s\n", ovs_strerror(error)); - ok = false; + if (!error_msg) { + free(CONST_CAST(void *, po.packet)); + free(po.ofpacts); + } } - } - if (ok) { - unixctl_command_reply(conn, ds_cstr(&reply)); - } else { - unixctl_command_reply_error(conn, ds_cstr(&reply)); - } - ds_destroy(&reply); + static void ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux_) + { + struct barrier_aux *aux = (struct barrier_aux *)aux_; + struct ofpbuf *msg; + int error; - if (!error_msg) { - free(CONST_CAST(void *, po.packet)); - free(po.ofpacts); - } - } + if (aux->conn) { + unixctl_command_reply_error(conn, "already waiting for barrier reply"); + return; + } - static void ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux_) - { - struct barrier_aux *aux = (struct barrier_aux *)aux_; - struct ofpbuf *msg; - int error; + msg = ofputil_encode_barrier_request( + static_cast(vconn_get_version(aux->vconn))); + error = vconn_send_block(aux->vconn, msg); + if (error) { + ofpbuf_delete(msg); + unixctl_command_reply_error(conn, ovs_strerror(error)); + } else { + aux->conn = conn; + } + } - if (aux->conn) { - unixctl_command_reply_error(conn, "already waiting for barrier reply"); - return; - } + static void ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) + { + int fd; - msg = ofputil_encode_barrier_request( - static_cast(vconn_get_version(aux->vconn))); - error = vconn_send_block(aux->vconn, msg); - if (error) { - ofpbuf_delete(msg); - unixctl_command_reply_error(conn, ovs_strerror(error)); - } else { - aux->conn = conn; - } - } + fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (fd < 0) { + unixctl_command_reply_error(conn, ovs_strerror(errno)); + return; + } - static void ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) - { - int fd; + fflush(stderr); + dup2(fd, STDERR_FILENO); + close(fd); + unixctl_command_reply(conn, NULL); + } - fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (fd < 0) { - unixctl_command_reply_error(conn, ovs_strerror(errno)); - return; - } + static void ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *blocked_) + { + bool *blocked = (bool *)blocked_; - fflush(stderr); - dup2(fd, STDERR_FILENO); - close(fd); - unixctl_command_reply(conn, NULL); - } + if (!*blocked) { + *blocked = true; + unixctl_command_reply(conn, NULL); + } else { + unixctl_command_reply(conn, "already blocking"); + } + } - static void ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) - { - bool *blocked = (bool *)blocked_; + static void ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *blocked_) + { + bool *blocked = (bool *)blocked_; - if (!*blocked) { - *blocked = true; - unixctl_command_reply(conn, NULL); - } else { - unixctl_command_reply(conn, "already blocking"); - } + if (*blocked) { + *blocked = false; + unixctl_command_reply(conn, NULL); + } else { + unixctl_command_reply(conn, "already unblocked"); + } + } + }; + + daemon_save_fd(STDERR_FILENO); + daemonize_start(false); + error = unixctl_server_create(unixctl_path, &server); + if (error) { + // ovs_fatal(error, "failed to create unixctl server"); + ACA_LOG_ERROR("%s", "failed to create unixctl server"); } + unixctl_command_register("exit", "", 0, 0, X::ofctl_exit, &exiting); + unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX, X::ofctl_send, vconn); + unixctl_command_register("ofctl/packet-out", "\"in_port= packet= actions=...\"", + 1, 1, X::unixctl_packet_out, vconn); + unixctl_command_register("ofctl/barrier", "", 0, 0, X::ofctl_barrier, &barrier_aux); + unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1, + X::ofctl_set_output_file, NULL); - static void ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) - { - bool *blocked = (bool *)blocked_; + unixctl_command_register("ofctl/block", "", 0, 0, X::ofctl_block, &blocked); + unixctl_command_register("ofctl/unblock", "", 0, 0, X::ofctl_unblock, &blocked); - if (*blocked) { - *blocked = false; - unixctl_command_reply(conn, NULL); - } else { - unixctl_command_reply(conn, "already unblocked"); - } - } - }; - - daemon_save_fd(STDERR_FILENO); - daemonize_start(false); - error = unixctl_server_create(unixctl_path, &server); - if (error) { - // ovs_fatal(error, "failed to create unixctl server"); - ACA_LOG_ERROR("%s", "failed to create unixctl server"); - } - unixctl_command_register("exit", "", 0, 0, X::ofctl_exit, &exiting); - unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX, X::ofctl_send, vconn); - unixctl_command_register("ofctl/packet-out", "\"in_port= packet= actions=...\"", - 1, 1, X::unixctl_packet_out, vconn); - unixctl_command_register("ofctl/barrier", "", 0, 0, X::ofctl_barrier, &barrier_aux); - unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1, - X::ofctl_set_output_file, NULL); + daemonize_complete(); - unixctl_command_register("ofctl/block", "", 0, 0, X::ofctl_block, &blocked); - unixctl_command_register("ofctl/unblock", "", 0, 0, X::ofctl_unblock, &blocked); + enum ofp_version version = static_cast(vconn_get_version(vconn)); + enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version(version); - daemonize_complete(); + for (;;) { + struct ofpbuf *b; + int retval; - enum ofp_version version = static_cast(vconn_get_version(vconn)); - enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version(version); + unixctl_server_run(server); - for (;;) { - struct ofpbuf *b; - int retval; + while (!blocked) { + enum ofptype type; - unixctl_server_run(server); + retval = vconn_recv(vconn, &b); + if (retval == EAGAIN) { + break; + } + run(retval, "vconn_recv"); - while (!blocked) { - enum ofptype type; + if (timestamp) { + char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ", time_wall_msec(), true); + fputs(s, stderr); + free(s); + } + ofptype_decode(&type, (ofp_header *)b->data); - retval = vconn_recv(vconn, &b); - if (retval == EAGAIN) { - break; - } - run(retval, "vconn_recv"); + ofp_print(stderr, b->data, b->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity + 2); + ports_to_show(bridge), verbosity + 2); + fflush(stderr); - if (timestamp) { - char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ", time_wall_msec(), true); - fputs(s, stderr); - free(s); - } - ofptype_decode(&type, (ofp_header *)b->data); - - ofp_print(stderr, b->data, b->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity + 2); - ports_to_show(bridge), tables_to_show(bridge), verbosity + 2); - fflush(stderr); - - switch ((int)type) { - case OFPTYPE_BARRIER_REPLY: - if (barrier_aux.conn) { - unixctl_command_reply(barrier_aux.conn, NULL); - barrier_aux.conn = NULL; - } - break; - - case OFPTYPE_ECHO_REQUEST: - if (reply_to_echo_requests) { - struct ofpbuf *reply; - - reply = ofputil_encode_echo_reply((ofp_header *)b->data); - retval = vconn_send_block(vconn, reply); - if (retval) { - // ovs_fatal(retval, "failed to send echo reply"); - ACA_LOG_ERROR("%s", "failed to send echo reply"); - } - } - break; - - case OFPTYPE_PACKET_IN: - if (resume_continuations) { - struct ofputil_packet_in pin; - struct ofpbuf continuation; - size_t total_lenp; - uint32_t buffer_idp; - - error = ofputil_decode_packet_in((ofp_header *)b->data, true, NULL, NULL, - &pin, &total_lenp, &buffer_idp, &continuation); - uint32_t in_port = pin.flow_metadata.flow.in_port.ofp_port; - /* + switch ((int)type) { + case OFPTYPE_BARRIER_REPLY: + if (barrier_aux.conn) { + unixctl_command_reply(barrier_aux.conn, NULL); + barrier_aux.conn = NULL; + } + break; + + //case OFPTYPE_ECHO_REQUEST: + // if (reply_to_echo_requests) { + // struct ofpbuf *reply; + + // reply = ofputil_encode_echo_reply((ofp_header *)b->data); + // retval = vconn_send_block(vconn, reply); + // if (retval) { + // // ovs_fatal(retval, "failed to send echo reply"); + // ACA_LOG_ERROR("%s", "failed to send echo reply"); + // } + // } + // break; + + case OFPTYPE_PACKET_IN: + if (resume_continuations) { + struct ofputil_packet_in pin; + struct ofpbuf continuation; + size_t total_lenp; + uint32_t buffer_idp; + + error = ofputil_decode_packet_in((ofp_header *)b->data, true, + NULL, NULL, &pin, &total_lenp, + &buffer_idp, &continuation); + uint32_t in_port = pin.flow_metadata.flow.in_port.ofp_port; + /* The pin.packet here has the same memory address, even after multiple calls. If you intent to store it somewhere, it is advised to make a copy of it. */ - ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); - - if (error) { - fprintf(stderr, "decoding packet-in failed: %s", - ofperr_to_string((ofperr)error)); - } else if (continuation.size) { - struct ofpbuf *reply; - - reply = ofputil_encode_resume(&pin, &continuation, protocol); - - fprintf(stderr, "send: "); - ofp_print(stderr, reply->data, reply->size, ports_to_show(bridge), - tables_to_show(bridge), - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - verbosity + 2); - fflush(stderr); - - retval = vconn_send_block(vconn, reply); - if (retval) { - // ovs_fatal(retval, "failed to send NXT_RESUME"); - ACA_LOG_ERROR("%s", "failed to send NXT_RESUME"); + ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); + + if (error) { + fprintf(stderr, "decoding packet-in failed: %s", + ofperr_to_string((ofperr)error)); + } else if (continuation.size) { + struct ofpbuf *reply; + + reply = ofputil_encode_resume(&pin, &continuation, protocol); + + fprintf(stderr, "send: "); + ofp_print(stderr, reply->data, reply->size, ports_to_show(bridge), + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + verbosity + 2); + fflush(stderr); + + retval = vconn_send_block(vconn, reply); + if (retval) { + // ovs_fatal(retval, "failed to send NXT_RESUME"); + ACA_LOG_ERROR("%s", "failed to send NXT_RESUME"); + } + } + } + break; } - } + ofpbuf_delete(b); } - break; - } - ofpbuf_delete(b); - } - if (exiting) { - break; - } - vconn_run(vconn); - vconn_run_wait(vconn); - if (!blocked) { - vconn_recv_wait(vconn); + if (exiting) { + break; + } + vconn_run(vconn); + vconn_run_wait(vconn); + if (!blocked) { + vconn_recv_wait(vconn); + } + unixctl_server_wait(server); + poll_block(); } - unixctl_server_wait(server); - poll_block(); - } - vconn_close(vconn); - unixctl_server_destroy(server); + vconn_close(vconn); + unixctl_server_destroy(server); } void OVS_Control::run(int retval, const char *message, ...) { - if (retval) { - va_list args; + if (retval) { + va_list args; - va_start(args, message); - ovs_fatal_valist(retval, message, args); - } + va_start(args, message); + ovs_fatal_valist(retval, message, args); + } } -bool OVS_Control::set_packet_in_format(vconn *vconn, enum ofputil_packet_in_format packet_in_format, +bool OVS_Control::set_packet_in_format(vconn *vconn, enum nx_packet_in_format packet_in_format, bool must_succeed) { - struct ofpbuf *spif; + struct ofpbuf *spif; - spif = ofputil_encode_set_packet_in_format( - static_cast(vconn_get_version(vconn)), packet_in_format); - if (must_succeed) { - transact_noreply(vconn, spif); - } else { - struct ofpbuf *reply; + //spif = ofputil_encode_set_packet_in_format( + spif = ofputil_make_set_packet_in_format( + static_cast(vconn_get_version(vconn)), packet_in_format); - run(vconn_transact_noreply(vconn, spif, &reply), "talking to %s", vconn_get_name(vconn)); - if (reply) { - char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2); - VLOG_DBG("%s: failed to set packet in format to nx_packet_in, " - "controller replied: %s.", - vconn_get_name(vconn), s); - free(s); - ofpbuf_delete(reply); - - return false; + if (must_succeed) { + transact_noreply(vconn, spif); } else { - VLOG_DBG("%s: using user-specified packet in format %s", vconn_get_name(vconn), - ofputil_packet_in_format_to_string(packet_in_format)); + struct ofpbuf *reply; + + run(vconn_transact_noreply(vconn, spif, &reply), "talking to %s", + vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, NULL, 2); + VLOG_DBG("%s: failed to set packet in format to nx_packet_in, " + "controller replied: %s.", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + + return false; + } } - } - return true; + return true; } void OVS_Control::bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags) { - struct ovs_list errors; - int retval = vconn_bundle_transact(vconn, requests, flags, &errors); + struct ovs_list errors; + int retval = vconn_bundle_transact(vconn, requests, flags, &errors); - bundle_print_errors(&errors, requests, vconn_get_name(vconn)); + bundle_print_errors(&errors, requests, vconn_get_name(vconn)); - if (retval) { - // ovs_fatal(retval, "talking to %s", vconn_get_name(vconn)); - ACA_LOG_ERROR("talking to %s", vconn_get_name(vconn)); - } + if (retval) { + // ovs_fatal(retval, "talking to %s", vconn_get_name(vconn)); + ACA_LOG_ERROR("talking to %s", vconn_get_name(vconn)); + } } /* Frees the error messages as they are printed. */ void OVS_Control::bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, const char *vconn_name) { - struct ofpbuf *error, *next; - struct ofpbuf *bmsg; + struct ofpbuf *error, *next; + struct ofpbuf *bmsg; - INIT_CONTAINER(bmsg, requests, list_node); + INIT_CONTAINER(bmsg, requests, list_node); - LIST_FOR_EACH_SAFE(error, next, list_node, errors) - { - const struct ofp_header *error_oh = (ofp_header *)error->data; - ovs_be32 error_xid = error_oh->xid; - enum ofperr ofperr; - struct ofpbuf payload; - - ofperr = ofperr_decode_msg(error_oh, &payload); - if (!ofperr) { - fprintf(stderr, "***decode error***"); - } else { - /* Default to the likely truncated message. */ - const struct ofp_header *ofp_msg = (ofp_header *)payload.data; - size_t msg_len = payload.size; + LIST_FOR_EACH_SAFE(error, next, list_node, errors) + { + const struct ofp_header *error_oh = (ofp_header *)error->data; + ovs_be32 error_xid = error_oh->xid; + enum ofperr ofperr; + struct ofpbuf payload; + + ofperr = ofperr_decode_msg(error_oh, &payload); + if (!ofperr) { + fprintf(stderr, "***decode error***"); + } else { + /* Default to the likely truncated message. */ + const struct ofp_header *ofp_msg = (ofp_header *)payload.data; + size_t msg_len = payload.size; - /* Find the failing message from the requests list to be able to + /* Find the failing message from the requests list to be able to * dump the whole message. We assume the errors are returned in * the same order as in which the messages are sent to get O(n) * rather than O(n^2) processing here. If this heuristics fails we * may print the truncated hexdumps instead. */ - LIST_FOR_EACH_CONTINUE(bmsg, list_node, requests) - { - const struct ofp_header *oh = (ofp_header *)bmsg->data; - - if (oh->xid == error_xid) { - ofp_msg = oh; - msg_len = bmsg->size; - break; + LIST_FOR_EACH_CONTINUE(bmsg, list_node, requests) + { + const struct ofp_header *oh = (ofp_header *)bmsg->data; + + if (oh->xid == error_xid) { + ofp_msg = oh; + msg_len = bmsg->size; + break; + } + } + fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr)); + ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name), verbosity + 1); } - } - fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr)); - ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name), - tables_to_show(vconn_name), verbosity + 1); + ofpbuf_uninit(&payload); + ofpbuf_delete(error); } - ofpbuf_uninit(&payload); - ofpbuf_delete(error); - } - fflush(stderr); + fflush(stderr); } /* Sends 'request', which should be a request that only has a reply if an error @@ -1156,11 +1164,11 @@ void OVS_Control::bundle_print_errors(struct ovs_list *errors, * Destroys 'request'. */ void OVS_Control::transact_noreply(vconn *vconn, ofpbuf *request) { - struct ovs_list requests; + struct ovs_list requests; - ovs_list_init(&requests); - ovs_list_push_back(&requests, &request->list_node); - transact_multiple_noreply(vconn, &requests); + ovs_list_init(&requests); + ovs_list_push_back(&requests, &request->list_node); + transact_multiple_noreply(vconn, &requests); } /* Sends all of the 'requests', which should be requests that only have replies @@ -1170,141 +1178,140 @@ void OVS_Control::transact_noreply(vconn *vconn, ofpbuf *request) * Destroys all of the 'requests'. */ void OVS_Control::transact_multiple_noreply(vconn *vconn, ovs_list *requests) { - struct ofpbuf *reply; - - run(vconn_transact_multiple_noreply(vconn, requests, &reply), "talking to %s", - vconn_get_name(vconn)); - if (reply) { - ofp_print(stderr, reply->data, reply->size, ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), verbosity + 2); - exit(1); - } - ofpbuf_delete(reply); + struct ofpbuf *reply; + + run(vconn_transact_multiple_noreply(vconn, requests, &reply), + "talking to %s", vconn_get_name(vconn)); + if (reply) { + ofp_print(stderr, reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), verbosity + 2); + exit(1); + } + ofpbuf_delete(reply); } void OVS_Control::send_openflow_buffer(vconn *vconn, ofpbuf *buffer) { - run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); + run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); } void OVS_Control::dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge) { - const ofp_header *oh = (ofp_header *)request->data; - if (ofpmsg_is_stat_request(oh)) { - ovs_be32 send_xid = oh->xid; - enum ofpraw request_raw; - enum ofpraw reply_raw; - bool done = false; - - ofpraw_decode_partial(&request_raw, (ofp_header *)request->data, request->size); - reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version); - - send_openflow_buffer(vconn, request); - while (!done) { - ovs_be32 recv_xid; - struct ofpbuf *reply; - - run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - recv_xid = ((struct ofp_header *)reply->data)->xid; - if (send_xid == recv_xid) { - enum ofpraw ofpraw; - ofp_print(stdout, reply->data, reply->size, ports_to_show(bridge), - tables_to_show(bridge), - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - verbosity + 1); - - ofpraw_decode(&ofpraw, (struct ofp_header *)reply->data); - if (ofptype_from_ofpraw(ofpraw) == OFPTYPE_ERROR) { - done = true; - } else if (ofpraw == reply_raw) { - done = !ofpmp_more((struct ofp_header *)reply->data); - } else { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string( - // reply->data, reply->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - // OVS_Control::verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(reply->data, reply->size, - ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), - OVS_Control::verbosity + 1)); + const ofp_header *oh = (ofp_header *)request->data; + if (ofpmsg_is_stat_request(oh)) { + ovs_be32 send_xid = oh->xid; + enum ofpraw request_raw; + enum ofpraw reply_raw; + bool done = false; + + ofpraw_decode_partial(&request_raw, (ofp_header *)request->data, request->size); + reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version); + + send_openflow_buffer(vconn, request); + while (!done) { + ovs_be32 recv_xid; + struct ofpbuf *reply; + + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); + recv_xid = ((struct ofp_header *)reply->data)->xid; + if (send_xid == recv_xid) { + enum ofpraw ofpraw; + ofp_print(stdout, reply->data, reply->size, ports_to_show(bridge), + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + verbosity + 1); + + ofpraw_decode(&ofpraw, (struct ofp_header *)reply->data); + if (ofptype_from_ofpraw(ofpraw) == OFPTYPE_ERROR) { + done = true; + } else if (ofpraw == reply_raw) { + done = !ofpmp_more((struct ofp_header *)reply->data); + } else { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string( + // reply->data, reply->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + // OVS_Control::verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), + OVS_Control::verbosity + 1)); + } + } else { + VLOG_DBG("received reply with xid %08" PRIx32 " " + "!= expected %08" PRIx32, + recv_xid, send_xid); + } + ofpbuf_delete(reply); } - } else { - VLOG_DBG("received reply with xid %08" PRIx32 " " - "!= expected %08" PRIx32, - recv_xid, send_xid); - } - ofpbuf_delete(reply); + } else { + struct ofpbuf *reply; + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); + ofp_print(stdout, reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), verbosity + 1); + ofpbuf_delete(reply); } - } else { - struct ofpbuf *reply; - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); - ofp_print(stdout, reply->data, reply->size, ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), verbosity + 1); - ofpbuf_delete(reply); - } } bool OVS_Control::str_to_ofp(const char *s, ofp_port_t *ofp_port) { - bool ret; - uint32_t port_; + bool ret; + uint32_t port_; - ret = str_to_uint(s, 10, &port_); - *ofp_port = OFP_PORT_C(port_); + ret = str_to_uint(s, 10, &port_); + *ofp_port = OFP_PORT_C(port_); - return ret; + return ret; } void OVS_Control::port_iterator_fetch_port_desc(port_iterator *pi) { - pi->variant = PI_PORT_DESC; - pi->more = true; + pi->variant = PI_PORT_DESC; + pi->more = true; - struct ofpbuf *rq = ofputil_encode_port_desc_stats_request( - static_cast(vconn_get_version(pi->vconn)), OFPP_ANY); - pi->send_xid = ((struct ofp_header *)rq->data)->xid; - send_openflow_buffer(pi->vconn, rq); + struct ofpbuf *rq = ofputil_encode_port_desc_stats_request( + static_cast(vconn_get_version(pi->vconn)), OFPP_ANY); + pi->send_xid = ((struct ofp_header *)rq->data)->xid; + send_openflow_buffer(pi->vconn, rq); } void OVS_Control::port_iterator_fetch_features(port_iterator *pi) { - pi->variant = PI_FEATURES; - - /* Fetch the switch's ofp_switch_features. */ - enum ofp_version version = static_cast(vconn_get_version(pi->vconn)); - struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0); - run(vconn_transact(pi->vconn, rq, &pi->reply), "talking to %s", vconn_get_name(pi->vconn)); - - enum ofptype type; - if (ofptype_decode(&type, (struct ofp_header *)pi->reply->data) || - type != OFPTYPE_FEATURES_REPLY) { - // ovs_fatal(0, "%s: received bad features reply", - // vconn_get_name(pi->vconn)); - ACA_LOG_ERROR("%s: received bad features reply", vconn_get_name(pi->vconn)); - } - if (!ofputil_switch_features_has_ports(pi->reply)) { - /* The switch features reply does not contain a complete list of ports. + pi->variant = PI_FEATURES; + + /* Fetch the switch's ofp_switch_features. */ + enum ofp_version version = static_cast(vconn_get_version(pi->vconn)); + struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0); + run(vconn_transact(pi->vconn, rq, &pi->reply), "talking to %s", + vconn_get_name(pi->vconn)); + + enum ofptype type; + if (ofptype_decode(&type, (struct ofp_header *)pi->reply->data) || + type != OFPTYPE_FEATURES_REPLY) { + // ovs_fatal(0, "%s: received bad features reply", + // vconn_get_name(pi->vconn)); + ACA_LOG_ERROR("%s: received bad features reply", vconn_get_name(pi->vconn)); + } + if (!ofputil_switch_features_has_ports(pi->reply)) { + /* The switch features reply does not contain a complete list of ports. * Probably, there are more ports than will fit into a single 64 kB * OpenFlow message. Use OFPST_PORT_DESC to get a complete list of * ports. */ - ofpbuf_delete(pi->reply); - pi->reply = NULL; - port_iterator_fetch_port_desc(pi); - return; - } + ofpbuf_delete(pi->reply); + pi->reply = NULL; + port_iterator_fetch_port_desc(pi); + return; + } - struct ofputil_switch_features features; - enum ofperr error = ofputil_pull_switch_features(pi->reply, &features); - if (error) { - // ovs_fatal(0, "%s: failed to decode features reply (%s)", - // vconn_get_name(pi->vconn), ofperr_to_string(error)); - ACA_LOG_ERROR("%s: failed to decode features reply (%s)", - vconn_get_name(pi->vconn), ofperr_to_string(error)); - } + struct ofputil_switch_features features; + enum ofperr error = ofputil_pull_switch_features(pi->reply, &features); + if (error) { + // ovs_fatal(0, "%s: failed to decode features reply (%s)", + // vconn_get_name(pi->vconn), ofperr_to_string(error)); + ACA_LOG_ERROR("%s: failed to decode features reply (%s)", + vconn_get_name(pi->vconn), ofperr_to_string(error)); + } } /* Initializes 'pi' to prepare for iterating through all of the ports on the @@ -1315,13 +1322,13 @@ void OVS_Control::port_iterator_fetch_features(port_iterator *pi) * iterator and thus some ports may be missed or a hang can occur. */ void OVS_Control::port_iterator_init(port_iterator *pi, vconn *vconn) { - memset(pi, 0, sizeof *pi); - pi->vconn = vconn; - if (vconn_get_version(vconn) < OFP13_VERSION) { - port_iterator_fetch_features(pi); - } else { - port_iterator_fetch_port_desc(pi); - } + memset(pi, 0, sizeof *pi); + pi->vconn = vconn; + if (vconn_get_version(vconn) < OFP13_VERSION) { + port_iterator_fetch_features(pi); + } else { + port_iterator_fetch_port_desc(pi); + } } /* Obtains the next port from 'pi'. On success, initializes '*pp' with the @@ -1329,60 +1336,60 @@ void OVS_Control::port_iterator_init(port_iterator *pi, vconn *vconn) * been seen), returns false. */ bool OVS_Control::port_iterator_next(port_iterator *pi, ofputil_phy_port *pp) { - for (;;) { - if (pi->reply) { - int retval = ofputil_pull_phy_port( - static_cast(vconn_get_version(pi->vconn)), pi->reply, pp); - if (!retval) { - return true; - } else if (retval != EOF) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(pi->reply->data, pi->reply->size, - // NULL, NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(pi->reply->data, pi->reply->size, NULL, - NULL, verbosity + 1)); - } - } + for (;;) { + if (pi->reply) { + int retval = ofputil_pull_phy_port( + static_cast(vconn_get_version(pi->vconn)), pi->reply, pp); + if (!retval) { + return true; + } else if (retval != EOF) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(pi->reply->data, pi->reply->size, + // NULL, NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(pi->reply->data, pi->reply->size, + NULL, verbosity + 1)); + } + } - if (pi->variant == PI_FEATURES || !pi->more) { - return false; - } + if (pi->variant == PI_FEATURES || !pi->more) { + return false; + } - ovs_be32 recv_xid; - do { - ofpbuf_delete(pi->reply); - run(vconn_recv_block(pi->vconn, &pi->reply), "OpenFlow receive failed"); - recv_xid = ((struct ofp_header *)pi->reply->data)->xid; - } while (pi->send_xid != recv_xid); + ovs_be32 recv_xid; + do { + ofpbuf_delete(pi->reply); + run(vconn_recv_block(pi->vconn, &pi->reply), "OpenFlow receive failed"); + recv_xid = ((struct ofp_header *)pi->reply->data)->xid; + } while (pi->send_xid != recv_xid); + + struct ofp_header *oh = (ofp_header *)pi->reply->data; + enum ofptype type; + if (ofptype_pull(&type, pi->reply) || type != OFPTYPE_PORT_DESC_STATS_REPLY) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(pi->reply->data, pi->reply->size, NULL, + // NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(pi->reply->data, pi->reply->size, NULL, + verbosity + 1)); + } - struct ofp_header *oh = (ofp_header *)pi->reply->data; - enum ofptype type; - if (ofptype_pull(&type, pi->reply) || type != OFPTYPE_PORT_DESC_STATS_REPLY) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(pi->reply->data, pi->reply->size, NULL, - // NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(pi->reply->data, pi->reply->size, NULL, NULL, - verbosity + 1)); + pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; } - - pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; - } } /* Destroys iterator 'pi'. */ void OVS_Control::port_iterator_destroy(port_iterator *pi) { - if (pi) { - while (pi->variant == PI_PORT_DESC && pi->more) { - /* Drain vconn's queue of any other replies for this request. */ - struct ofputil_phy_port pp; - port_iterator_next(pi, &pp); - } + if (pi) { + while (pi->variant == PI_PORT_DESC && pi->more) { + /* Drain vconn's queue of any other replies for this request. */ + struct ofputil_phy_port pp; + port_iterator_next(pi, &pp); + } - ofpbuf_delete(pi->reply); - } + ofpbuf_delete(pi->reply); + } } /* Opens a connection to 'vconn_name', fetches the port structure for @@ -1391,33 +1398,33 @@ void OVS_Control::port_iterator_destroy(port_iterator *pi) void OVS_Control::fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, ofputil_phy_port *pp) { - struct vconn *vconn; - ofp_port_t port_no; - bool found = false; + struct vconn *vconn; + ofp_port_t port_no; + bool found = false; - /* Try to interpret the argument as a port number. */ - if (!str_to_ofp(port_name, &port_no)) { - port_no = OFPP_NONE; - } + /* Try to interpret the argument as a port number. */ + if (!str_to_ofp(port_name, &port_no)) { + port_no = OFPP_NONE; + } - /* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the + /* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the * OFPT_FEATURES_REPLY message. OpenFlow 1.3 and later versions put it * into the OFPST_PORT_DESC reply. Try it the correct way. */ - open_vconn(vconn_name, &vconn); - struct port_iterator pi; - for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp);) { - if (port_no != OFPP_NONE ? port_no == pp->port_no : !strcmp(pp->name, port_name)) { - found = true; - break; + open_vconn(vconn_name, &vconn); + struct port_iterator pi; + for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp);) { + if (port_no != OFPP_NONE ? port_no == pp->port_no : !strcmp(pp->name, port_name)) { + found = true; + break; + } } - } - port_iterator_destroy(&pi); - vconn_close(vconn); + port_iterator_destroy(&pi); + vconn_close(vconn); - if (!found) { - // ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name); - ACA_LOG_ERROR("%s: couldn't find port `%s'", vconn_name, port_name); - } + if (!found) { + // ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name); + ACA_LOG_ERROR("%s: couldn't find port `%s'", vconn_name, port_name); + } } /* Initializes 'ti' to prepare for iterating through all of the tables on the @@ -1428,127 +1435,130 @@ void OVS_Control::fetch_ofputil_phy_port(const char *vconn_name, * iterator and thus some tables may be missed or a hang can occur. */ void OVS_Control::table_iterator_init(table_iterator *ti, vconn *vconn) { - memset(ti, 0, sizeof *ti); - ti->vconn = vconn; - ti->variant = (vconn_get_version(vconn) < OFP13_VERSION ? TI_STATS : TI_FEATURES); - ti->more = true; - - enum ofpraw ofpraw = (ti->variant == TI_STATS ? OFPRAW_OFPST_TABLE_REQUEST : - OFPRAW_OFPST13_TABLE_FEATURES_REQUEST); - struct ofpbuf *rq = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0); - ti->send_xid = ((struct ofp_header *)rq->data)->xid; - send_openflow_buffer(ti->vconn, rq); + memset(ti, 0, sizeof *ti); + ti->vconn = vconn; + ti->variant = (vconn_get_version(vconn) < OFP13_VERSION ? TI_STATS : TI_FEATURES); + ti->more = true; + + enum ofpraw ofpraw = (ti->variant == TI_STATS ? OFPRAW_OFPST_TABLE_REQUEST : + OFPRAW_OFPST13_TABLE_FEATURES_REQUEST); + struct ofpbuf *rq = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0); + ti->send_xid = ((struct ofp_header *)rq->data)->xid; + send_openflow_buffer(ti->vconn, rq); } /* Obtains the next table from 'ti'. On success, returns the next table's * features; on failure, returns NULL. */ const ofputil_table_features *OVS_Control::table_iterator_next(table_iterator *ti) { - for (;;) { - if (ti->reply) { - int retval; - if (ti->variant == TI_STATS) { - struct ofputil_table_stats ts; - retval = ofputil_decode_table_stats_reply(ti->reply, &ts, &ti->features); - } else { - ovs_assert(ti->variant == TI_FEATURES); - retval = ofputil_decode_table_features(ti->reply, &ti->features, &ti->raw_properties); - } - if (!retval) { - return &ti->features; - } else if (retval != EOF) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(ti->reply->data, ti->reply->size, - // NULL, NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(ti->reply->data, ti->reply->size, NULL, - NULL, verbosity + 1)); - } - } + for (;;) { + if (ti->reply) { + int retval; + if (ti->variant == TI_STATS) { + struct ofputil_table_stats ts; + retval = ofputil_decode_table_stats_reply(ti->reply, &ts, &ti->features); + } else { + ovs_assert(ti->variant == TI_FEATURES); + retval = ofputil_decode_table_features(ti->reply, &ti->features, + &ti->raw_properties); + } + if (!retval) { + return &ti->features; + } else if (retval != EOF) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(ti->reply->data, ti->reply->size, + // NULL, NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(ti->reply->data, ti->reply->size, + NULL, verbosity + 1)); + } + } - if (!ti->more) { - return NULL; - } + if (!ti->more) { + return NULL; + } - ovs_be32 recv_xid; - do { - ofpbuf_delete(ti->reply); - run(vconn_recv_block(ti->vconn, &ti->reply), "OpenFlow receive failed"); - recv_xid = ((struct ofp_header *)ti->reply->data)->xid; - } while (ti->send_xid != recv_xid); + ovs_be32 recv_xid; + do { + ofpbuf_delete(ti->reply); + run(vconn_recv_block(ti->vconn, &ti->reply), "OpenFlow receive failed"); + recv_xid = ((struct ofp_header *)ti->reply->data)->xid; + } while (ti->send_xid != recv_xid); + + struct ofp_header *oh = (ofp_header *)ti->reply->data; + enum ofptype type; + if (ofptype_pull(&type, ti->reply) || + type != (ti->variant == TI_STATS ? OFPTYPE_TABLE_STATS_REPLY : + OFPTYPE_TABLE_FEATURES_STATS_REPLY)) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(ti->reply->data, ti->reply->size, NULL, + // NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(ti->reply->data, ti->reply->size, NULL, + verbosity + 1)); + } - struct ofp_header *oh = (ofp_header *)ti->reply->data; - enum ofptype type; - if (ofptype_pull(&type, ti->reply) || - type != (ti->variant == TI_STATS ? OFPTYPE_TABLE_STATS_REPLY : - OFPTYPE_TABLE_FEATURES_STATS_REPLY)) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(ti->reply->data, ti->reply->size, NULL, - // NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(ti->reply->data, ti->reply->size, NULL, NULL, - verbosity + 1)); + ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; } - - ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; - } } /* Destroys iterator 'ti'. */ void OVS_Control::table_iterator_destroy(table_iterator *ti) { - if (ti) { - while (ti->more) { - /* Drain vconn's queue of any other replies for this request. */ - table_iterator_next(ti); - } + if (ti) { + while (ti->more) { + /* Drain vconn's queue of any other replies for this request. */ + table_iterator_next(ti); + } - ofpbuf_delete(ti->reply); - } + ofpbuf_delete(ti->reply); + } } const ofputil_port_map *OVS_Control::get_port_map(const char *vconn_name) { - static shash port_maps = SHASH_INITIALIZER(&port_maps); - struct ofputil_port_map *map = (ofputil_port_map *)shash_find_data(&port_maps, vconn_name); - if (!map) { - map = (ofputil_port_map *)malloc(sizeof *map); - ofputil_port_map_init(map); - shash_add(&port_maps, vconn_name, map); - if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { - /* For an active vconn (which includes a vconn constructed from a + static shash port_maps = SHASH_INITIALIZER(&port_maps); + struct ofputil_port_map *map = + (ofputil_port_map *)shash_find_data(&port_maps, vconn_name); + if (!map) { + map = (ofputil_port_map *)malloc(sizeof *map); + ofputil_port_map_init(map); + shash_add(&port_maps, vconn_name, map); + if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { + /* For an active vconn (which includes a vconn constructed from a * bridge name), connect to it and pull down the port name-number * mapping. */ - struct vconn *vconn; - open_vconn(vconn_name, &vconn); + struct vconn *vconn; + open_vconn(vconn_name, &vconn); - struct port_iterator pi; - struct ofputil_phy_port pp; - for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp);) { - ofputil_port_map_put(map, pp.port_no, pp.name); - } - port_iterator_destroy(&pi); + struct port_iterator pi; + struct ofputil_phy_port pp; + for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp);) { + ofputil_port_map_put(map, pp.port_no, pp.name); + } + port_iterator_destroy(&pi); - vconn_close(vconn); - } else { - /* Don't bother with passive vconns, since it could take a long + vconn_close(vconn); + } else { + /* Don't bother with passive vconns, since it could take a long * time for the remote to try to connect to us. Don't bother with * invalid vconn names either. */ + } } - } - return map; + return map; } const ofputil_port_map *OVS_Control::ports_to_accept(const char *vconn_name) { - return should_accept_names() ? get_port_map(vconn_name) : NULL; + return should_accept_names() ? get_port_map(vconn_name) : NULL; } const ofputil_port_map *OVS_Control::ports_to_show(const char *vconn_name) { - return should_show_names() ? get_port_map(vconn_name) : NULL; + return should_show_names() ? get_port_map(vconn_name) : NULL; } +/* const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) { static shash table_maps = SHASH_INITIALIZER(&table_maps); @@ -1559,9 +1569,9 @@ const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) shash_add(&table_maps, vconn_name, map); if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { - /* For an active vconn (which includes a vconn constructed from a - * bridge name), connect to it and pull down the port name-number - * mapping. */ + // For an active vconn (which includes a vconn constructed from a + // * bridge name), connect to it and pull down the port name-number + // * mapping. struct vconn *vconn; open_vconn(vconn_name, &vconn); @@ -1580,9 +1590,9 @@ const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) vconn_close(vconn); } else { - /* Don't bother with passive vconns, since it could take a long - * time for the remote to try to connect to us. Don't bother with - * invalid vconn names either. */ + // Don't bother with passive vconns, since it could take a long + // * time for the remote to try to connect to us. Don't bother with + // * invalid vconn names either. } } return map; @@ -1597,23 +1607,24 @@ const ofputil_table_map *OVS_Control::tables_to_show(const char *vconn_name) { return should_show_names() ? get_table_map(vconn_name) : NULL; } +*/ /* We accept port and table names unless the feature is turned off explicitly. */ bool OVS_Control::should_accept_names(void) { - return use_names != 0; + return use_names != 0; } /* We show port and table names only if the feature is turned on explicitly, or * if we're interacting with a user on the console. */ bool OVS_Control::should_show_names(void) { - static int interactive = -1; - if (interactive == -1) { - interactive = isatty(STDOUT_FILENO); - } + static int interactive = -1; + if (interactive == -1) { + interactive = isatty(STDOUT_FILENO); + } - return use_names > 0 || (use_names == -1 && interactive); + return use_names > 0 || (use_names == -1 && interactive); } } // namespace ovs_control From 877e7f6031bda44c7051860341d02e682154fa0e Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Mon, 16 Aug 2021 21:36:42 -0700 Subject: [PATCH 02/54] Launch openflow controller in aca_main --- .clang-format | 2 +- src/aca_main.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 7de93f24..9c0091df 100644 --- a/.clang-format +++ b/.clang-format @@ -440,7 +440,7 @@ IncludeCategories: IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false #IndentPPDirectives: None # Unknown to clang-format-5.0 -IndentWidth: 2 +IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 1b8a9563..9a26f877 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -272,7 +272,6 @@ int main(int argc, char *argv[]) g_grpc_server_thread->detach(); // Create a separate thread to run the grpc client. - g_grpc_client = new GoalStateProvisionerClientImpl(); g_grpc_client_thread = new std::thread( std::bind(&GoalStateProvisionerClientImpl::RunClient, g_grpc_client)); From a792e89813a784b7142579f2628423f27285f9f4 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Wed, 18 Aug 2021 14:07:55 -0700 Subject: [PATCH 03/54] Integration with main --- src/CMakeLists.txt | 4 ---- src/aca_main.cpp | 7 ++++--- src/grpc/CMakeLists.txt | 2 +- src/proto3/CMakeLists.txt | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 730cecb6..3c439944 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,19 +57,15 @@ find_path(LIBEVENT_INCLUDE_DIR REQUIRED) FIND_LIBRARY(LIBUUID_LIBRARIES uuid) -#FIND_LIBRARY(LIBEVENT libevent) FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu NO_DEFAULT_PATH) FIND_LIBRARY(CPPKAFKA cppkafka /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(PULSAR pulsar /usr/lib NO_DEFAULT_PATH) -#FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../include NO_DEFAULT_PATH) -#link_libraries(${RDKAFKA} ${CPPKAFKA} ${OPENVSWITCH} ${PULSAR}) link_libraries(${RDKAFKA} ${CPPKAFKA} ${PULSAR}) link_libraries(/usr/lib/x86_64-linux-gnu/libuuid.so) link_libraries(/usr/lib/x86_64-linux-gnu/libevent_pthreads.so) link_libraries(/usr/lib/x86_64-linux-gnu/libpthread.so) link_libraries(/root/lfu/code/openvswitch-2.9.8/lib/.libs/libopenvswitch.a) -#include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${OPENVSWITCH_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/proto3) diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 9a26f877..df8e949b 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -14,7 +14,6 @@ #include "aca_log.h" #include "aca_util.h" -#include "aca_ovs_control.h" #include "aca_message_pulsar_consumer.h" #include "aca_grpc.h" #include "aca_grpc_client.h" @@ -286,8 +285,8 @@ int main(int argc, char *argv[]) return rc; } - // start ovs server and point br-int/br-tun's controller to local ovs server - std::unordered_map switch_dpid_map = + // get bridge-dpid mappings from ovs + std::unordered_map switch_dpid_map = aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_ovs_bridge_mapping(); // set bridge controller will clean up flows @@ -296,6 +295,7 @@ int main(int argc, char *argv[]) // then add default ovs flows aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_default_flows(); + // start local ovs server (openflow controller) g_ovs_ctrl = new OFController(switch_dpid_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); g_ovs_ctrl->start(); @@ -311,5 +311,6 @@ int main(int argc, char *argv[]) ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); rc = network_config_consumer.consumeDispatched(g_pulsar_topic); aca_cleanup(); + return rc; } diff --git a/src/grpc/CMakeLists.txt b/src/grpc/CMakeLists.txt index 959b6b8f..20342e5d 100644 --- a/src/grpc/CMakeLists.txt +++ b/src/grpc/CMakeLists.txt @@ -17,7 +17,7 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) # Proto file -get_filename_component(aca_proto "../../alcor/schema/proto3/*.proto" ABSOLUTE) +get_filename_component(aca_proto "../../../alcor/schema/proto3/*.proto" ABSOLUTE) get_filename_component(aca_proto_path "${aca_proto}" PATH) set(aca_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/goalstateprovisioner.pb.cc") diff --git a/src/proto3/CMakeLists.txt b/src/proto3/CMakeLists.txt index c5e41f20..01d67763 100644 --- a/src/proto3/CMakeLists.txt +++ b/src/proto3/CMakeLists.txt @@ -1,6 +1,6 @@ INCLUDE(FindProtobuf) FIND_PACKAGE(Protobuf REQUIRED) INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) -file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/../../alcor/schema/proto3/*.proto") +file(GLOB ProtoFiles "../../../alcor/schema/proto3/*.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) ADD_LIBRARY(proto ${ProtoHeaders} ${ProtoSources}) From 223ee0789609ffb5c278a4ec409167bec90dbf36 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 26 Aug 2021 17:34:37 -0700 Subject: [PATCH 04/54] Prepare ovs dependencies in init script --- build/aca-machine-init.sh | 19 ++++++++++--------- src/CMakeLists.txt | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index a8ab98d3..761ffaa2 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -105,17 +105,18 @@ echo "5--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ -OVS_RELEASE_TAG="branch-2.12" echo "6--- installing openvswitch dependancies ---" && \ - git clone -b $OVS_RELEASE_TAG https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + apt-get install libevent-dev && \ + mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ - ./boot.sh && \ - ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ - make && \ - make install && \ - cp /var/local/git/openvswitch/lib/vconn-provider.h /usr/local/include/openvswitch/vconn-provider.h && \ - rm -rf /var/local/git/openvswitch && \ - test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ + git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ + tar -xvzf openvswitch-2.9.8.tar.gz && \ + cd openvswitch-2.9.8 && \ + ./configure && make && \ # compile ovs 2.9.8 release version + make install && \ # install ovs lib and header files + cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ cd ~ PULSAR_RELEASE_TAG='pulsar-2.6.1' diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c439944..3accc472 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,7 +65,7 @@ link_libraries(${RDKAFKA} ${CPPKAFKA} ${PULSAR}) link_libraries(/usr/lib/x86_64-linux-gnu/libuuid.so) link_libraries(/usr/lib/x86_64-linux-gnu/libevent_pthreads.so) link_libraries(/usr/lib/x86_64-linux-gnu/libpthread.so) -link_libraries(/root/lfu/code/openvswitch-2.9.8/lib/.libs/libopenvswitch.a) +link_libraries(/usr/local/lib/libopenvswitch.a) #this was installed by aca-machine-init.sh include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/proto3) From e0270d8e3216819e239c53defb947b4041c95e1a Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 10:06:47 -0700 Subject: [PATCH 05/54] Revert relative path to locate proto files --- src/grpc/CMakeLists.txt | 4 ++-- src/proto3/CMakeLists.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grpc/CMakeLists.txt b/src/grpc/CMakeLists.txt index 20342e5d..194cf43c 100644 --- a/src/grpc/CMakeLists.txt +++ b/src/grpc/CMakeLists.txt @@ -17,7 +17,7 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) # Proto file -get_filename_component(aca_proto "../../../alcor/schema/proto3/*.proto" ABSOLUTE) +get_filename_component(aca_proto "../../alcor/schema/proto3/*.proto" ABSOLUTE) get_filename_component(aca_proto_path "${aca_proto}" PATH) set(aca_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/goalstateprovisioner.pb.cc") @@ -37,4 +37,4 @@ add_custom_command( # Include generated *.pb.h files include_directories("${CMAKE_CURRENT_BINARY_DIR}") -ADD_LIBRARY(grpc ${aca_proto_srcs} ${aca_proto_hdrs} ${aca_grpc_srcs} ${aca_grpc_hdrs}) +ADD_LIBRARY(grpc ${aca_proto_srcs} ${aca_proto_hdrs} ${aca_grpc_srcs} ${aca_grpc_hdrs}) \ No newline at end of file diff --git a/src/proto3/CMakeLists.txt b/src/proto3/CMakeLists.txt index 01d67763..e72e0b7a 100644 --- a/src/proto3/CMakeLists.txt +++ b/src/proto3/CMakeLists.txt @@ -1,6 +1,6 @@ INCLUDE(FindProtobuf) FIND_PACKAGE(Protobuf REQUIRED) INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) -file(GLOB ProtoFiles "../../../alcor/schema/proto3/*.proto") +file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/../../alcor/schema/proto3/*.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) -ADD_LIBRARY(proto ${ProtoHeaders} ${ProtoSources}) +ADD_LIBRARY(proto ${ProtoHeaders} ${ProtoSources}) \ No newline at end of file From 5d305c9f3f109fe4d08b4842001ae928fefa5d35 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 10:56:24 -0700 Subject: [PATCH 06/54] Fix relative path to proto files for grpc folder --- src/grpc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grpc/CMakeLists.txt b/src/grpc/CMakeLists.txt index 194cf43c..aa9daeb2 100644 --- a/src/grpc/CMakeLists.txt +++ b/src/grpc/CMakeLists.txt @@ -17,7 +17,7 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) # Proto file -get_filename_component(aca_proto "../../alcor/schema/proto3/*.proto" ABSOLUTE) +get_filename_component(aca_proto "${CMAKE_CURRENT_SOURCE_DIR}/../../alcor/schema/proto3/*.proto" ABSOLUTE) get_filename_component(aca_proto_path "${aca_proto}" PATH) set(aca_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/goalstateprovisioner.pb.cc") From 23b93b22215b0b22fecc534aabc99361efb963c0 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 11:16:08 -0700 Subject: [PATCH 07/54] Also prepare ovs dependencies in docker preparation --- build/Dockerfile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 69462dea..fb14d71e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -108,22 +108,22 @@ RUN echo "4--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ -ENV OVS_RELEASE_TAG branch-2.12 RUN echo "5--- installing openvswitch dependancies ---" && \ - git clone -b ${OVS_RELEASE_TAG} https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + apt-get install libevent-dev && \ + mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ - ./boot.sh && \ - ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ - make && \ - make install && \ - mkdir -p /usr/local/include/openvswitch && \ - cp /var/local/git/openvswitch/lib/vconn-provider.h /usr/local/include/openvswitch/vconn-provider.h && \ - rm -rf /var/local/git/openvswitch && \ - test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ + git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ + tar -xvzf openvswitch-2.9.8.tar.gz && \ + cd openvswitch-2.9.8 && \ + ./configure && make && \ # compile ovs 2.9.8 release version + make install && \ # install ovs lib and header files + cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ cd ~ ENV PULSAR_RELEASE_TAG='pulsar-2.6.1' -RUN echo "7--- installing pulsar dependacies ---" && \ +RUN echo "6--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client-dev.deb -O /var/local/git/pulsar/apache-pulsar-client-dev.deb && \ From afbf42966a104b3cc961bf121c718bd2261bf732 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 11:21:48 -0700 Subject: [PATCH 08/54] Fix docker file --- build/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index fb14d71e..df096f53 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -116,8 +116,8 @@ RUN echo "5--- installing openvswitch dependancies ---" && \ wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ tar -xvzf openvswitch-2.9.8.tar.gz && \ cd openvswitch-2.9.8 && \ - ./configure && make && \ # compile ovs 2.9.8 release version - make install && \ # install ovs lib and header files + ./configure && make && \ + make install && \ cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ cd ~ From 767ea55c4892f0f6fe7af9e8931bd73eeafde676 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 11:38:54 -0700 Subject: [PATCH 09/54] Force apt get install in docker file --- build/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Dockerfile b/build/Dockerfile index df096f53..b7e26a42 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -109,7 +109,7 @@ RUN echo "4--- cloning grpc repo ---" && \ cd ~ RUN echo "5--- installing openvswitch dependancies ---" && \ - apt-get install libevent-dev && \ + apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ From e4452eb077130c8220bb2045e5e581fa838b04f3 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 27 Aug 2021 12:11:32 -0700 Subject: [PATCH 10/54] Fix ovs dependency and installation --- build/Dockerfile | 7 +++++++ build/aca-machine-init.sh | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index b7e26a42..9305cf0e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -113,6 +113,11 @@ RUN echo "5--- installing openvswitch dependancies ---" && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + ./boot.sh && \ + ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ + make && \ + make install && \ + cd /var/local/git/openvswitch && \ wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ tar -xvzf openvswitch-2.9.8.tar.gz && \ cd openvswitch-2.9.8 && \ @@ -120,6 +125,8 @@ RUN echo "5--- installing openvswitch dependancies ---" && \ make install && \ cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + rm -rf /var/local/git/openvswitch && \ + test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ ENV PULSAR_RELEASE_TAG='pulsar-2.6.1' diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 761ffaa2..2fdf369c 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -106,17 +106,24 @@ echo "5--- cloning grpc repo ---" && \ cd ~ echo "6--- installing openvswitch dependancies ---" && \ - apt-get install libevent-dev && \ + apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + ./boot.sh && \ + ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ + make && \ + make install && \ + cd /var/local/git/openvswitch && \ wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ tar -xvzf openvswitch-2.9.8.tar.gz && \ cd openvswitch-2.9.8 && \ - ./configure && make && \ # compile ovs 2.9.8 release version - make install && \ # install ovs lib and header files + ./configure && make && \ + make install && \ cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + rm -rf /var/local/git/openvswitch && \ + test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ PULSAR_RELEASE_TAG='pulsar-2.6.1' From 79574ad158c7361d71f685860add3f8a6daf222b Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Mon, 30 Aug 2021 19:48:39 -0700 Subject: [PATCH 11/54] Call openflow execution from OFConnection instead, otherwise flows auto deleted after added via ovs control vconn --- include/aca_ovs_l2_programmer.h | 13 +++- include/aca_zeta_oam_server.h | 2 +- include/of_controller.h | 8 ++- include/of_message.h | 4 +- src/aca_main.cpp | 6 +- src/dhcp/aca_dhcp_server.cpp | 23 ++++--- src/ovs/aca_arp_responder.cpp | 7 +- src/ovs/aca_ovs_l2_programmer.cpp | 68 +++++++++---------- src/ovs/aca_ovs_l3_programmer.cpp | 108 ++++++++++++++++++------------ src/ovs/aca_vlan_manager.cpp | 28 +++++--- src/ovs/of_controller.cpp | 42 ++++++++++++ src/zeta/aca_zeta_oam_server.cpp | 19 ++++-- test/gtest/aca_test_oam.cpp | 7 +- test/gtest/aca_test_openflow.cpp | 11 ++- test/gtest/aca_test_ovs_util.cpp | 7 +- 15 files changed, 233 insertions(+), 120 deletions(-) diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index 41d556ba..2c65801d 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -16,6 +16,8 @@ #define ACA_OVS_L2_PROGRAMMER_H #include "goalstateprovisioner.grpc.pb.h" +#undef UNUSED +#include "of_controller.h" #include #include @@ -38,10 +40,10 @@ class ACA_OVS_L2_Programmer { int setup_ovs_bridges_if_need(); - int setup_ovs_default_flows(); - int setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port); + void set_openflow_controller(OFController* ofctrl); + std::unordered_map get_ovs_bridge_mapping(); int create_port(const std::string vpc_id, const std::string port_name, @@ -64,11 +66,18 @@ class ACA_OVS_L2_Programmer { void execute_openflow_command(const std::string cmd_string, ulong &culminative_time, int &overall_rc); + void execute_openflow(ulong &culminative_time, + const std::string bridge, + const std::string flow_string, + const std::string action = "add"); + // compiler will flag the error when below is called. ACA_OVS_L2_Programmer(ACA_OVS_L2_Programmer const &) = delete; void operator=(ACA_OVS_L2_Programmer const &) = delete; private: + OFController* ofctrl; + ACA_OVS_L2_Programmer(){}; ~ACA_OVS_L2_Programmer(){}; }; diff --git a/include/aca_zeta_oam_server.h b/include/aca_zeta_oam_server.h index c25e8367..14988640 100644 --- a/include/aca_zeta_oam_server.h +++ b/include/aca_zeta_oam_server.h @@ -19,7 +19,7 @@ #include #include #include -#include +//#include #include "hashmap/HashMap.h" #include "goalstateprovisioner.grpc.pb.h" diff --git a/include/of_controller.h b/include/of_controller.h index 05613c1a..d65a2ed2 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -59,9 +59,9 @@ class OFController : public OFServer { void remove_switch_from_conn_map(int ofconn_id); - void send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p); + void setup_default_flows(); - void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); + void execute_flow(const std::string br, const std::string flow_str, const std::string action = "add"); private: // tracking xid (ovs transaction id) @@ -77,4 +77,8 @@ class OFController : public OFServer { std::unordered_map switch_dpid_map; std::mutex switch_map_mutex; + + void send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p); + + void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); }; diff --git a/include/of_message.h b/include/of_message.h index 0e324001..4456c6d6 100644 --- a/include/of_message.h +++ b/include/of_message.h @@ -74,6 +74,6 @@ class BundleReplyMessage { }; ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle = false); -ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict, bool bundle = false); -ofmsg_ptr_t create_del_flow(const std::string& match, bool strict, bool bundle = false); +ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict); +ofmsg_ptr_t create_del_flow(const std::string& match, bool strict); std::vector create_add_flows(const std::vector& flows, bool bundle = false); diff --git a/src/aca_main.cpp b/src/aca_main.cpp index df8e949b..333b2084 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -292,13 +292,13 @@ int main(int argc, char *argv[]) // set bridge controller will clean up flows aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_controller(g_ovs_ctrl_address, g_ovs_ctrl_port); - // then add default ovs flows - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_default_flows(); - // start local ovs server (openflow controller) g_ovs_ctrl = new OFController(switch_dpid_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); g_ovs_ctrl->start(); + // pass ovs_ctrl to l2 programmer + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().set_openflow_controller(g_ovs_ctrl); + // monitor br-int for dhcp request message ovs_monitor_brint_thread = new thread(bind(&ACA_OVS_Control::monitor, diff --git a/src/dhcp/aca_dhcp_server.cpp b/src/dhcp/aca_dhcp_server.cpp index 49bf09b1..0d061c62 100644 --- a/src/dhcp/aca_dhcp_server.cpp +++ b/src/dhcp/aca_dhcp_server.cpp @@ -20,9 +20,14 @@ #include #include #include -#include "aca_ovs_control.h" #include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace aca_dhcp_programming_if; @@ -63,24 +68,24 @@ void ACA_Dhcp_Server::_deinit_dhcp_db() void ACA_Dhcp_Server::_init_dhcp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; // adding dhcp default flows - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "add-flow br-int \"table=0,priority=25,udp,udp_src=68,udp_dst=67,actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-int", + "table=0,priority=25,udp,udp_src=68,udp_dst=67,actions=CONTROLLER", + "add"); return; } void ACA_Dhcp_Server::_deinit_dhcp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; // deleting dhcp default flows - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "del-flows br-int \"udp,udp_src=68,udp_dst=67\"", - not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-int", + "udp,udp_src=68,udp_dst=67", + "del"); return; } diff --git a/src/ovs/aca_arp_responder.cpp b/src/ovs/aca_arp_responder.cpp index 8bb0b5c7..9e81e0fb 100644 --- a/src/ovs/aca_arp_responder.cpp +++ b/src/ovs/aca_arp_responder.cpp @@ -62,10 +62,11 @@ void ACA_ARP_Responder::_init_arp_ofp() void ACA_ARP_Responder::_deinit_arp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "del-flows br-tun \"arp,arp_op=1\"", not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-tun", + "arp,arp_op=1", + "del"); return; } diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index 33655d8b..617b0b1c 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -93,6 +93,11 @@ ACA_OVS_L2_Programmer &ACA_OVS_L2_Programmer::get_instance() return instance; } +void ACA_OVS_L2_Programmer::set_openflow_controller(OFController* ofctrl) +{ + this->ofctrl = ofctrl; +} + bool ACA_OVS_L2_Programmer::is_ip_on_the_same_host(const std::string host_ip) { return std::find(this->host_ips_vector.begin(), this->host_ips_vector.end(), @@ -250,40 +255,6 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() return overall_rc; } -int ACA_OVS_L2_Programmer::setup_ovs_default_flows() -{ - // adding default flows - // details at: https://github.com/futurewei-cloud/alcor-control-agent/wiki/Openflow-Tables-Explain - int overall_rc = EXIT_SUCCESS; - ulong not_care_culminative_time; - - execute_openflow_command("add-flow br-tun \"table=0,priority=50,arp,arp_op=1, actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=20,priority=1 actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=52,priority=1 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)\"", - not_care_culminative_time, overall_rc); - - return overall_rc; -} - int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port) { int rc = EXIT_SUCCESS; @@ -610,4 +581,33 @@ void ACA_OVS_L2_Programmer::execute_openflow_command(const std::string cmd_strin ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::execute_openflow_command <--- Exiting, rc = %d\n", rc); } +void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, + const std::string bridge, + const std::string flow_string, + const std::string action) +{ + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Entering\n"); + auto openflow_client_start = chrono::steady_clock::now(); + + if (NULL != ofctrl) { + ofctrl->execute_flow(bridge, flow_string, action); + } else { + ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::execute_openflow didn't find OF controller\n"); + } + + auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + + culminative_time += openflow_client_time_total_time; + + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Exiting\n"); +} + } // namespace aca_ovs_l2_programmer diff --git a/src/ovs/aca_ovs_l3_programmer.cpp b/src/ovs/aca_ovs_l3_programmer.cpp index 14c1cc01..8912fa8e 100644 --- a/src/ovs/aca_ovs_l3_programmer.cpp +++ b/src/ovs/aca_ovs_l3_programmer.cpp @@ -238,24 +238,28 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ // Program ICMP responder: cmd_string = - "add-flow br-tun \"table=52,priority=50,icmp,dl_vlan=" + + "table=52,priority=50,icmp,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + found_gateway_ip + " actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:" + found_gateway_mac + ",move:NXM_OF_IP_SRC[]->NXM_OF_IP_DST[],mod_nw_src:" + found_gateway_ip + - ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port\""; + ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "add"); // Should be able to ping the gateway now // add essential rule to restore from neighbor host DVR mac to destination GW mac: // Note: all port from the same subnet on current host will share this rule - cmd_string = "add-flow br-int \"table=0,priority=25,dl_vlan=" + + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + ",dl_src=" + HOST_DVR_MAC_MATCH + - " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL\""; + " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "add"); for (int k = 0; k < current_subnet_routing_table.routing_rules_size(); k++) { auto current_routing_rule = current_subnet_routing_table.routing_rules(k); @@ -349,27 +353,29 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ if (current_fixed_ip.subnet_id() != current_subnet_routing_table.subnet_id()) { cmd_string = - "add-flow br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + current_routing_rule.destination() + ",dl_dst=" + found_gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + gw_mac + - ",mod_dl_dst:" + virtual_mac_address + ",output:IN_PORT\""; + ",mod_dl_dst:" + virtual_mac_address + ",output:IN_PORT"; } } else { cmd_string = - "add-flow br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + current_routing_rule.destination() + ",dl_dst=" + found_gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + _host_dvr_mac + - ",mod_dl_dst:" + virtual_mac_address + ",resubmit(,2)\""; + ",mod_dl_dst:" + virtual_mac_address + ",resubmit(,2)"; } - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_dataplane_programming_time, + "br-tun", + cmd_string, + "add"); } } if (strcmp(remote_host_ip, "") != 0) { @@ -392,12 +398,14 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ int source_vlan_id = ACA_Vlan_Manager::get_instance().get_or_create_vlan_id(found_tunnel_id); string cmd_string = - "del-flows br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",dl_dst=" + found_gateway_mac + - ",nw_dst=" + current_routing_rule.destination() + "\" --strict"; + ",nw_dst=" + current_routing_rule.destination(); - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_dataplane_programming_time, + "br-tun", + cmd_string, + "del"); if (new_subnet_routing_table_entry.routing_rules.erase( current_routing_rule.id())) { ACA_LOG_INFO("Successfuly cleaned up entry for router rule id %s\n", @@ -549,20 +557,24 @@ int ACA_OVS_L3_Programmer::delete_router(RouterConfiguration ¤t_RouterConf stArpCfg.ipv4_address.c_str(), source_vlan_id); // Delete ICMP responder: - cmd_string = "del-flows br-tun \"table=52,icmp,dl_vlan=" + to_string(source_vlan_id) + - ",nw_dst=" + subnet_it->second.gateway_ip + "\""; + cmd_string = "table=52,icmp,dl_vlan=" + to_string(source_vlan_id) + + ",nw_dst=" + subnet_it->second.gateway_ip; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "del"); // remove essential rule which restore from neighbor host DVR mac to destination GW mac // Note: all port from the same subnet on current host will share this rule - cmd_string = "del-flows br-int \"table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + - ",dl_src=" + HOST_DVR_MAC_MATCH + "\" --strict"; + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + + ",dl_src=" + HOST_DVR_MAC_MATCH; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "del"); } // -----critical section starts----- @@ -762,25 +774,29 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ // Program ICMP responder: cmd_string = - "add-flow br-tun \"table=52,priority=50,icmp,dl_vlan=" + + "table=52,priority=50,icmp,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + found_gateway_ip + " actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:" + found_gateway_mac + ",move:NXM_OF_IP_SRC[]->NXM_OF_IP_DST[],mod_nw_src:" + found_gateway_ip + - ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port\""; + ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "add"); // Should be able to ping the gateway now // add essential rule to restore from neighbor host DVR mac to destination GW mac: // Note: all port from the same subnet on current host will share this rule - cmd_string = "add-flow br-int \"table=0,priority=25,dl_vlan=" + + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + ",dl_src=" + HOST_DVR_MAC_MATCH + - " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL\""; + " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "add"); for (int k = 0; k < current_subnet_routing_table.routing_rules_size(); k++) { auto current_routing_rule = current_subnet_routing_table.routing_rules(k); @@ -987,23 +1003,25 @@ int ACA_OVS_L3_Programmer::create_or_update_l3_neighbor( // the openflow rule depends on whether the hosting ip is on this compute host or not if (is_port_on_same_host) { - cmd_string = "add-flow br-tun \"table=0,priority=25,ip,dl_vlan=" + + cmd_string = "table=0,priority=25,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + ",dl_dst=" + subnet_it->second.gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + destination_gw_mac + - ",mod_dl_dst:" + virtual_mac + ",output:IN_PORT\""; + ",mod_dl_dst:" + virtual_mac + ",output:IN_PORT"; } else { - cmd_string = "add-flow br-tun \"table=0,priority=25,ip,dl_vlan=" + + cmd_string = "table=0,priority=25,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + ",dl_dst=" + subnet_it->second.gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + _host_dvr_mac + - ",mod_dl_dst:" + virtual_mac + ",resubmit(,2)\""; + ",mod_dl_dst:" + virtual_mac + ",resubmit(,2)"; } - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "add"); } // we found our interested router from _routers_table which has the destination subnet GW connected to it. // Since each subnet GW can only be connected to one router, therefore, there is no point to look at other @@ -1085,11 +1103,13 @@ int ACA_OVS_L3_Programmer::delete_l3_neighbor(const string neighbor_id, const st // for the first implementation with static routing rules (non on-demand) // go ahead to remove it - string cmd_string = "del-flows br-tun \"table=0,priority=50,ip,dl_vlan=" + - to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + "\" --strict"; + string cmd_string = "table=0,priority=50,ip,dl_vlan=" + + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "del"); // once we have the on demand routing rule implemented, we will need remove any // on demand routing rule assoicated this deleted neighbor to stop the traffic diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index 87900edd..377a905c 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -15,9 +15,15 @@ #include "aca_log.h" #include "aca_util.h" #include "aca_vlan_manager.h" -#include "aca_ovs_control.h" #include "aca_ovs_l2_programmer.h" #include "aca_arp_responder.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + #include #include #include @@ -119,11 +125,13 @@ int ACA_Vlan_Manager::create_ovs_port(string /*vpc_id*/, string ovs_port, int internal_vlan_id = current_vpc_table_entry->vlan_id; string cmd_string = - "add-flow br-tun \"table=4, priority=1,tun_id=" + to_string(tunnel_id) + - " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:\"patch-int\"\""; + "table=4, priority=1,tun_id=" + to_string(tunnel_id) + + " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:\"patch-int\""; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "add"); current_vpc_table_entry->ovs_ports.insert(ovs_port, nullptr); } @@ -154,11 +162,13 @@ int ACA_Vlan_Manager::delete_ovs_port(string /*vpc_id*/, string ovs_port, // also delete the rule assoicated with the VPC: // table 4 = incoming vxlan, allow incoming vxlan traffic matching tunnel_id // to stamp with internal vlan and deliver to br-int - string cmd_string = "del-flows br-tun \"table=4, priority=1,tun_id=" + - to_string(tunnel_id) + "\" --strict"; + string cmd_string = "table=4, priority=1,tun_id=" + + to_string(tunnel_id); - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "del"); } } diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index c59add80..49065a05 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -163,4 +163,46 @@ void OFController::send_bundle_flow_mods(OFConnection *ofconn, std::vectorsend(buf_commit_req->data(), buf_commit_req->len()); ACA_LOG_INFO("OFController::send_bundle_flow_mods - ovs connection id=%d send bundle commit request of bundle_id %ld\n", ofconn->get_id(), bundle.get_bundle_id()); +} + +void OFController::setup_default_flows() { + // all default flows are added to 'br-tun' only + OFConnection* ofconn_br_tun = get_instance("br-tun"); + + if (NULL != ofconn_br_tun) { + send_packet(ofconn_br_tun, create_add_flow("table=0,priority=50,arp,arp_op=1, actions=CONTROLLER")); + send_packet(ofconn_br_tun, create_add_flow("table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)")); + send_packet(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)")); + send_packet(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)")); + send_packet(ofconn_br_tun, create_add_flow("table=20,priority=1 actions=CONTROLLER")); + send_packet(ofconn_br_tun, create_add_flow("table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)")); + send_packet(ofconn_br_tun, create_add_flow("table=52,priority=1 actions=resubmit(,20)")); + send_packet(ofconn_br_tun, create_add_flow("table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)")); + } else { + ACA_LOG_ERROR("OFController::setup_default_flows - ovs connection of br-tun not found\n"); + } + + ofconn_br_tun = NULL; +} + +void OFController::execute_flow(const std::string br, const std::string flow_str, const std::string action) { + OFConnection* ofconn_br = get_instance(br); + + if (NULL != ofconn_br) { + if (action == "add") { + send_packet(ofconn_br, create_add_flow(flow_str)); + } else if (action == "mod") { + // --strict mod + send_packet(ofconn_br, create_mod_flow(flow_str, true)); + } else if (action == "del") { + // --strict del + send_packet(ofconn_br, create_del_flow(flow_str, true)); + } else { + ACA_LOG_ERROR("OFController::execute_flow - action %s not supported in flow %s\n", action.c_str(), flow_str.c_str()); + } + } else { + ACA_LOG_ERROR("OFController::execute_flow - ovs connection of br-tun not found\n"); + } + + ofconn_br = NULL; } \ No newline at end of file diff --git a/src/zeta/aca_zeta_oam_server.cpp b/src/zeta/aca_zeta_oam_server.cpp index 25a2b123..424784ec 100644 --- a/src/zeta/aca_zeta_oam_server.cpp +++ b/src/zeta/aca_zeta_oam_server.cpp @@ -18,15 +18,20 @@ #include #include #include -#include "aca_ovs_l2_programmer.h" #include "aca_util.h" -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_zeta_programming.h" #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_l2_programmer.h" +//#include "aca_ovs_control.h" + using namespace std; -using namespace aca_ovs_control; +//using namespace aca_ovs_control; namespace aca_zeta_oam_server { @@ -289,16 +294,18 @@ int ACA_Zeta_Oam_Server::_add_direct_path(oam_match match, oam_action action) int ACA_Zeta_Oam_Server::_del_direct_path(oam_match match) { + unsigned long not_care_culminative_time; int overall_rc; string vlan_id = to_string(aca_vlan_manager::ACA_Vlan_Manager::get_instance().get_or_create_vlan_id( match.vni)); - string opt = "table=20,priority=50,ip,nw_proto=" + match.proto + + string opt = "del-flows br-tun \"table=20,priority=50,ip,nw_proto=" + match.proto + ",nw_src=" + match.sip + ",nw_dst=" + match.dip + - ",tp_src=" + match.sport + ",tp_dst=" + match.dport + ",dl_vlan=" + vlan_id; + ",tp_src=" + match.sport + ",tp_dst=" + match.dport + ",dl_vlan=" + vlan_id + "\" --strict"; // delete flow - overall_rc = ACA_OVS_Control::get_instance().del_flows("br-tun", opt.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( + opt, not_care_culminative_time, overall_rc); if (overall_rc == EXIT_SUCCESS) { ACA_LOG_INFO("%s", "Delete direct path succeeded!\n"); diff --git a/test/gtest/aca_test_oam.cpp b/test/gtest/aca_test_oam.cpp index a2560c37..ea7d8631 100644 --- a/test/gtest/aca_test_oam.cpp +++ b/test/gtest/aca_test_oam.cpp @@ -18,11 +18,16 @@ #include "aca_zeta_oam_server.h" #include "aca_util.h" #include -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_zeta_programming.h" #include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace aca_zeta_oam_server; using namespace aca_ovs_control; using namespace aca_zeta_programming; diff --git a/test/gtest/aca_test_openflow.cpp b/test/gtest/aca_test_openflow.cpp index d254e3e4..36a18379 100644 --- a/test/gtest/aca_test_openflow.cpp +++ b/test/gtest/aca_test_openflow.cpp @@ -14,14 +14,19 @@ #include "aca_util.h" #include "gtest/gtest.h" -#include "aca_ovs_control.h" -#include "ovs_control.h" +//#include "ovs_control.h" #include "aca_ovs_l2_programmer.h" #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace aca_ovs_control; -using namespace ovs_control; +//using namespace ovs_control; using aca_ovs_l2_programmer::ACA_OVS_L2_Programmer; extern string vmac_address_1; diff --git a/test/gtest/aca_test_ovs_util.cpp b/test/gtest/aca_test_ovs_util.cpp index dcfeb985..1a059674 100644 --- a/test/gtest/aca_test_ovs_util.cpp +++ b/test/gtest/aca_test_ovs_util.cpp @@ -15,7 +15,6 @@ #include "aca_log.h" #include "aca_util.h" #include "aca_config.h" -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_ovs_l2_programmer.h" #include "aca_ovs_l3_programmer.h" @@ -26,6 +25,12 @@ #include #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace alcor::schema; using namespace aca_comm_manager; From c8141635b28b216a3dbb97f9c97a77c870515972 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Tue, 31 Aug 2021 10:05:11 -0700 Subject: [PATCH 12/54] setup default flow --- src/ovs/of_controller.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index 49065a05..02836f6d 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -38,6 +38,11 @@ void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* da // parse which bridge is the connection from std::string bridge_name = switch_dpid_map[dpid]; add_switch_to_conn_map(bridge_name, ofconn->get_id(), ofconn); + + // when br-tun is connected, setup default flow + if (bridge_name == "br-tun") { + setup_default_flows(); + } } } else if (type == fluid_msg::of13::OFPT_BARRIER_REPLY) { auto t = std::chrono::high_resolution_clock::now(); From 49ba59ae70fcebafaf0e4b353546963324aef6b0 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Wed, 1 Sep 2021 20:02:51 -0700 Subject: [PATCH 13/54] Integrate with packet-in and packet-out for dhcp and on-demand --- build/Dockerfile | 55 ++++++- build/aca-machine-init.sh | 56 ++++++- build/test.sh | 200 +++++++++++++++++++++++++ include/aca_on_demand_engine.h | 1 + include/aca_ovs_l2_programmer.h | 4 + include/of_controller.h | 15 +- include/of_message.h | 1 + src/aca_main.cpp | 33 ++-- src/dhcp/aca_dhcp_server.cpp | 6 +- src/on_demand/aca_on_demand_engine.cpp | 13 +- src/ovs/aca_arp_responder.cpp | 6 +- src/ovs/aca_ovs_l2_programmer.cpp | 59 +++++++- src/ovs/of_controller.cpp | 54 +++++-- src/ovs/of_message.cpp | 24 ++- 14 files changed, 479 insertions(+), 48 deletions(-) create mode 100644 build/test.sh diff --git a/build/Dockerfile b/build/Dockerfile index 9305cf0e..e8403e21 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -108,23 +108,72 @@ RUN echo "4--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ +ENV OVS_INCLUDE_HEADERS='include/openvswitch/compiler.h \ + include/openvswitch/dynamic-string.h \ + include/openvswitch/hmap.h \ + include/openvswitch/flow.h \ + include/openvswitch/geneve.h \ + include/openvswitch/json.h \ + include/openvswitch/list.h \ + include/openvswitch/netdev.h \ + include/openvswitch/match.h \ + include/openvswitch/meta-flow.h \ + include/openvswitch/ofpbuf.h \ + include/openvswitch/ofp-actions.h \ + include/openvswitch/ofp-ed-props.h \ + include/openvswitch/ofp-errors.h \ + include/openvswitch/ofp-msgs.h \ + include/openvswitch/ofp-parse.h \ + include/openvswitch/ofp-print.h \ + include/openvswitch/ofp-prop.h \ + include/openvswitch/ofp-util.h \ + include/openvswitch/packets.h \ + include/openvswitch/poll-loop.h \ + include/openvswitch/rconn.h \ + include/openvswitch/shash.h \ + include/openvswitch/thread.h \ + include/openvswitch/token-bucket.h \ + include/openvswitch/tun-metadata.h \ + include/openvswitch/type-props.h \ + include/openvswitch/types.h \ + include/openvswitch/util.h \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ + include/openvswitch/vlog.h \ + include/openvswitch/nsh.h ' +ENV OPENFLOW_HEADERS='include/openflow/intel-ext.h \ + include/openflow/netronome-ext.h \ + include/openflow/nicira-ext.h \ + include/openflow/openflow-1.0.h \ + include/openflow/openflow-1.1.h \ + include/openflow/openflow-1.2.h \ + include/openflow/openflow-1.3.h \ + include/openflow/openflow-1.4.h \ + include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ + include/openflow/openflow-common.h \ + include/openflow/openflow.h ' RUN echo "5--- installing openvswitch dependancies ---" && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + cd /var/local/git/openvswitch && \ ./boot.sh && \ ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ make && \ make install && \ + cp ./lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp ./include/openvswitch/namemap.h /usr/local/include/openvswitch && \ cd /var/local/git/openvswitch && \ wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ tar -xvzf openvswitch-2.9.8.tar.gz && \ cd openvswitch-2.9.8 && \ ./configure && make && \ - make install && \ - cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ - cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + cp ${OVS_INCLUDE_HEADERS} /usr/local/include/openvswitch && \ + cp ${OPENFLOW_HEADERS} /usr/local/include/openflow && \ + cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ rm -rf /var/local/git/openvswitch && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 2fdf369c..2399f284 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -105,23 +105,71 @@ echo "5--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ +OVS_INCLUDE_HEADERS="include/openvswitch/compiler.h \ + include/openvswitch/dynamic-string.h \ + include/openvswitch/hmap.h \ + include/openvswitch/flow.h \ + include/openvswitch/geneve.h \ + include/openvswitch/json.h \ + include/openvswitch/list.h \ + include/openvswitch/netdev.h \ + include/openvswitch/match.h \ + include/openvswitch/meta-flow.h \ + include/openvswitch/ofpbuf.h \ + include/openvswitch/ofp-actions.h \ + include/openvswitch/ofp-ed-props.h \ + include/openvswitch/ofp-errors.h \ + include/openvswitch/ofp-msgs.h \ + include/openvswitch/ofp-parse.h \ + include/openvswitch/ofp-print.h \ + include/openvswitch/ofp-prop.h \ + include/openvswitch/ofp-util.h \ + include/openvswitch/packets.h \ + include/openvswitch/poll-loop.h \ + include/openvswitch/rconn.h \ + include/openvswitch/shash.h \ + include/openvswitch/thread.h \ + include/openvswitch/token-bucket.h \ + include/openvswitch/tun-metadata.h \ + include/openvswitch/type-props.h \ + include/openvswitch/types.h \ + include/openvswitch/util.h \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ + include/openvswitch/vlog.h \ + include/openvswitch/nsh.h " +OPENFLOW_HEADERS="include/openflow/intel-ext.h \ + include/openflow/netronome-ext.h \ + include/openflow/nicira-ext.h \ + include/openflow/openflow-1.0.h \ + include/openflow/openflow-1.1.h \ + include/openflow/openflow-1.2.h \ + include/openflow/openflow-1.3.h \ + include/openflow/openflow-1.4.h \ + include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ + include/openflow/openflow-common.h \ + include/openflow/openflow.h " echo "6--- installing openvswitch dependancies ---" && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ - cd /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + cd /var/local/git/openvswitch && \ ./boot.sh && \ ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ make && \ make install && \ + cp ./lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp ./include/openvswitch/namemap.h /usr/local/include/openvswitch && \ cd /var/local/git/openvswitch && \ wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ tar -xvzf openvswitch-2.9.8.tar.gz && \ cd openvswitch-2.9.8 && \ ./configure && make && \ - make install && \ - cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ - cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + cp $OVS_INCLUDE_HEADERS /usr/local/include/openvswitch && \ + cp $OPENFLOW_HEADERS /usr/local/include/openflow && \ + cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ rm -rf /var/local/git/openvswitch && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ diff --git a/build/test.sh b/build/test.sh new file mode 100644 index 00000000..e9772ea9 --- /dev/null +++ b/build/test.sh @@ -0,0 +1,200 @@ +# MIT License +# Copyright(c) 2020 Futurewei Cloud +# +# Permission is hereby granted, +# free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#!/bin/bash + +BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +echo "build path is $BUILD" + +# TODO: remove the unneeded dependencies +echo "1--- installing mizar dependencies ---" && \ + apt-get update -y && apt-get install -y \ + rpcbind \ + rsyslog \ + build-essential \ + clang-9 \ + llvm-9 \ + libelf-dev \ + iproute2 \ + net-tools \ + iputils-ping \ + ethtool \ + curl \ + python3 \ + python3-pip \ + netcat \ + libcmocka-dev \ + lcov +pip3 install httpserver netaddr + +echo "2--- installing librdkafka ---" && \ + apt-get update -y && apt-get install -y --no-install-recommends\ + librdkafka-dev \ + doxygen \ + libssl-dev \ + zlib1g-dev \ + libboost-program-options-dev \ + libboost-all-dev \ + && apt-get clean + +echo "3--- installing cppkafka ---" && \ + apt-get update -y && apt-get install -y cmake + git clone https://github.com/mfontanini/cppkafka.git /var/local/git/cppkafka && \ + cd /var/local/git/cppkafka && \ + mkdir build && \ + cd build && \ + cmake .. && \ + make && \ + make install && \ + ldconfig && \ + rm -rf /var/local/git/cppkafka + cd ~ + +echo "4--- installing grpc dependencies ---" && \ + apt-get update -y && apt-get install -y \ + cmake libssl-dev \ + autoconf git pkg-config \ + automake libtool make g++ unzip + +# installing grpc and its dependencies +GRPC_RELEASE_TAG="v1.24.x" +echo "5--- cloning grpc repo ---" && \ + git clone -b $GRPC_RELEASE_TAG https://github.com/grpc/grpc /var/local/git/grpc && \ + cd /var/local/git/grpc && \ + git submodule update --init && \ + echo "--- installing c-ares ---" && \ + cd /var/local/git/grpc/third_party/cares/cares && \ + git fetch origin && \ + git checkout cares-1_15_0 && \ + mkdir -p cmake/build && \ + cd cmake/build && \ + cmake -DCMAKE_BUILD_TYPE=Release ../.. && \ + make -j4 install && \ + cd ../../../../.. && \ + rm -rf third_party/cares/cares && \ + echo "--- installing protobuf ---" && \ + cd /var/local/git/grpc/third_party/protobuf && \ + mkdir -p cmake/build && \ + cd cmake/build && \ + cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release .. && \ + make -j4 install && \ + cd ../../../.. && \ + rm -rf third_party/protobuf && \ + echo "--- installing grpc ---" && \ + cd /var/local/git/grpc && \ + mkdir -p cmake/build && \ + cd cmake/build && \ + cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release ../.. && \ + make -j4 install && \ + echo "--- installing google test ---" && \ + cd /var/local/git/grpc/third_party/googletest && \ + cmake -Dgtest_build_samples=ON -DBUILD_SHARED_LIBS=ON . && \ + make && \ + make install && \ + rm -rf /var/local/git/grpc && \ + cd ~ + +OVS_RELEASE_TAG="branch-2.12" +OVS_INCLUDE_HEADERS = \ + include/openvswitch/compiler.h \ + include/openvswitch/dynamic-string.h \ + include/openvswitch/hmap.h \ + include/openvswitch/flow.h \ + include/openvswitch/geneve.h \ + include/openvswitch/json.h \ + include/openvswitch/list.h \ + include/openvswitch/netdev.h \ + include/openvswitch/match.h \ + include/openvswitch/meta-flow.h \ + include/openvswitch/ofpbuf.h \ + include/openvswitch/ofp-actions.h \ + include/openvswitch/ofp-ed-props.h \ + include/openvswitch/ofp-errors.h \ + include/openvswitch/ofp-msgs.h \ + include/openvswitch/ofp-parse.h \ + include/openvswitch/ofp-print.h \ + include/openvswitch/ofp-prop.h \ + include/openvswitch/ofp-util.h \ + include/openvswitch/packets.h \ + include/openvswitch/poll-loop.h \ + include/openvswitch/rconn.h \ + include/openvswitch/shash.h \ + include/openvswitch/thread.h \ + include/openvswitch/token-bucket.h \ + include/openvswitch/tun-metadata.h \ + include/openvswitch/type-props.h \ + include/openvswitch/types.h \ + include/openvswitch/util.h \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ + include/openvswitch/vlog.h \ + include/openvswitch/nsh.h +OPENFLOW_HEADERS = \ + include/openflow/intel-ext.h \ + include/openflow/netronome-ext.h \ + include/openflow/nicira-ext.h \ + include/openflow/openflow-1.0.h \ + include/openflow/openflow-1.1.h \ + include/openflow/openflow-1.2.h \ + include/openflow/openflow-1.3.h \ + include/openflow/openflow-1.4.h \ + include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ + include/openflow/openflow-common.h \ + include/openflow/openflow.h +echo "6--- installing openvswitch dependancies ---" && \ + git clone -b $OVS_RELEASE_TAG https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + cd /var/local/git/openvswitch && \ + ./boot.sh && \ + ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ + make && \ + make install && \ + cd /var/local/git/openvswitch && \ + wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ + tar -xvzf openvswitch-2.9.8.tar.gz && \ + cd openvswitch-2.9.8 && \ + ./configure && make && \ + cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + cp $OVS_INCLUDE_HEADERS /usr/local/include/openvswitch && \ + cp $OPENFLOW_HEADERS /usr/local/include/openflow && \ + cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ + rm -rf /var/local/git/openvswitch && \ + test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ + cd ~ + +PULSAR_RELEASE_TAG='pulsar-2.6.1' +echo "7--- installing pulsar dependacies ---" && \ + mkdir -p /var/local/git/pulsar && \ + wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ + wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client-dev.deb -O /var/local/git/pulsar/apache-pulsar-client-dev.deb && \ + cd /var/local/git/pulsar && \ + apt install -y ./apache-pulsar-client*.deb && \ + rm -rf /var/local/git/pulsar + cd ~ + +echo "8--- building alcor-control-agent" +cd $BUILD/.. && cmake . && make + +if [ "$1" == "delete-bridges" ]; then + echo "9--- deleting br-tun and br-int if requested" + PATH=$PATH:/usr/local/share/openvswitch/scripts \ + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib + ovs-ctl --system-id=random --delete-bridges restart +fi + +echo "10--- running alcor-control-agent" +# sends output to null device, but stderr to console +nohup $BUILD/bin/AlcorControlAgent -d > /dev/null 2>&1 & diff --git a/include/aca_on_demand_engine.h b/include/aca_on_demand_engine.h index 577610e3..2629826f 100644 --- a/include/aca_on_demand_engine.h +++ b/include/aca_on_demand_engine.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "hashmap/HashMap.h" #include #include diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index 2c65801d..80e1054e 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -36,6 +36,8 @@ class ACA_OVS_L2_Programmer { void get_local_host_ips(); + std::unordered_map get_system_port_ids(); + bool is_ip_on_the_same_host(const std::string hosting_port_ip); int setup_ovs_bridges_if_need(); @@ -71,6 +73,8 @@ class ACA_OVS_L2_Programmer { const std::string flow_string, const std::string action = "add"); + void packet_out(const char *bridge, const char *options); + // compiler will flag the error when below is called. ACA_OVS_L2_Programmer(ACA_OVS_L2_Programmer const &) = delete; void operator=(ACA_OVS_L2_Programmer const &) = delete; diff --git a/include/of_controller.h b/include/of_controller.h index d65a2ed2..bbebd0d4 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -33,14 +33,16 @@ using namespace fluid_msg; class OFController : public OFServer { public: OFController(const std::unordered_map switch_dpid_map, + const std::unordered_map port_id_map, const char* address = "0.0.0.0", const int port = 1234, - const int nthreads = 8, + const int nthreads = 4, bool secure = false) : xid(0), switch_dpid_map(switch_dpid_map), + port_id_map(port_id_map), OFServer(address, port, nthreads, secure, - OFServerSettings().supported_version(5) + OFServerSettings().supported_version(4) // OF version 0x04 is OF 1.3 .echo_interval(30)) { } ~OFController() = default; @@ -63,6 +65,8 @@ class OFController : public OFServer { void execute_flow(const std::string br, const std::string flow_str, const std::string action = "add"); + void packet_out(const char* br, const char* opt); + private: // tracking xid (ovs transaction id) std::atomic xid; @@ -76,9 +80,14 @@ class OFController : public OFServer { // k is dpid (query from ovs), v is bridge name associated with it std::unordered_map switch_dpid_map; + // k is port name like (patch-int/tun and vxlan-generic), v is ofport id of it from ovsdb + std::unordered_map port_id_map; + std::mutex switch_map_mutex; - void send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p); + void send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p); + + void send_packet_out(OFConnection *ofconn, OFRawBuf* po); void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); }; diff --git a/include/of_message.h b/include/of_message.h index 4456c6d6..75cb129f 100644 --- a/include/of_message.h +++ b/include/of_message.h @@ -77,3 +77,4 @@ ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle = false); ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict); ofmsg_ptr_t create_del_flow(const std::string& match, bool strict); std::vector create_add_flows(const std::vector& flows, bool bundle = false); +OFRawBuf* create_packet_out(const char* bridge, const char* option); \ No newline at end of file diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 333b2084..e5a37788 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -30,6 +30,7 @@ #include "goalstateprovisioner.grpc.pb.h" #include +#include #include /* for getopt */ #include #include @@ -53,8 +54,8 @@ using namespace std; // Global variables std::thread *g_grpc_server_thread = NULL; std::thread *g_grpc_client_thread = NULL; -std::thread *ovs_monitor_brtun_thread = NULL; -std::thread *ovs_monitor_brint_thread = NULL; +//std::thread *ovs_monitor_brtun_thread = NULL; +//std::thread *ovs_monitor_brint_thread = NULL; GoalStateProvisionerAsyncServer *g_grpc_server = NULL; GoalStateProvisionerClientImpl *g_grpc_client = NULL; string g_broker_list = EMPTY_STRING; @@ -83,7 +84,7 @@ std::atomic_ulong g_total_vpcs_table_mutex_time(0); std::atomic_ulong g_total_update_GS_time(0); bool g_demo_mode = false; -bool g_debug_mode = false; +bool g_debug_mode = true; int processor_count = std::thread::hardware_concurrency(); /* From previous tests, we found that, for x number of cores, @@ -228,7 +229,7 @@ int main(int argc, char *argv[]) case 'd': g_debug_mode = true; break; - default: /* the '?' case when the option is not recognized */ + default: //the '?' case when the option is not recognized fprintf(stderr, "Usage: %s\n" "\t\t[-a NCM IP Address]\n" @@ -285,28 +286,32 @@ int main(int argc, char *argv[]) return rc; } - // get bridge-dpid mappings from ovs + // get bridge and dpid mappings from ovs std::unordered_map switch_dpid_map = aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_ovs_bridge_mapping(); + // get system port name and ofportid mappings from ovs + std::unordered_map port_id_map = + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_system_port_ids(); + // set bridge controller will clean up flows aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_controller(g_ovs_ctrl_address, g_ovs_ctrl_port); // start local ovs server (openflow controller) - g_ovs_ctrl = new OFController(switch_dpid_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); + g_ovs_ctrl = new OFController(switch_dpid_map, port_id_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); g_ovs_ctrl->start(); - // pass ovs_ctrl to l2 programmer + // pass ovs_ctrl handle to l2 programmer aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().set_openflow_controller(g_ovs_ctrl); - // monitor br-int for dhcp request message - ovs_monitor_brint_thread = - new thread(bind(&ACA_OVS_Control::monitor, - &ACA_OVS_Control::get_instance(), "br-int", "resume")); - ovs_monitor_brint_thread->detach(); + //// monitor br-int for dhcp request message + //ovs_monitor_brint_thread = + // new thread(bind(&ACA_OVS_Control::monitor, + // &ACA_OVS_Control::get_instance(), "br-int", "resume")); + //ovs_monitor_brint_thread->detach(); - // monitor br-tun for arp request message - ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); + //// monitor br-tun for arp request message + //ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); rc = network_config_consumer.consumeDispatched(g_pulsar_topic); diff --git a/src/dhcp/aca_dhcp_server.cpp b/src/dhcp/aca_dhcp_server.cpp index 0d061c62..06ec3f1e 100644 --- a/src/dhcp/aca_dhcp_server.cpp +++ b/src/dhcp/aca_dhcp_server.cpp @@ -325,8 +325,10 @@ void ACA_Dhcp_Server::dhcps_xmit(uint32_t inport, void *message) //bridge = "br-int" opts = "in_port=controller packet= actions=normal" options = in_port + whitespace + packetpre + packet + whitespace + action; - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), - options.c_str()); + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), + // options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out(bridge.c_str(), + options.c_str()); delete dhcpmsg; } diff --git a/src/on_demand/aca_on_demand_engine.cpp b/src/on_demand/aca_on_demand_engine.cpp index 804363e7..7c53e8ef 100644 --- a/src/on_demand/aca_on_demand_engine.cpp +++ b/src/on_demand/aca_on_demand_engine.cpp @@ -14,9 +14,7 @@ #include "aca_config.h" #include "aca_net_config.h" -#include "aca_on_demand_engine.h" #include "aca_vlan_manager.h" -#include "aca_ovs_control.h" #include "aca_grpc.h" #include "aca_grpc_client.h" #include "aca_log.h" @@ -35,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +40,12 @@ #include "goalstateprovisioner.pb.h" #include "aca_dhcp_server.h" #include "aca_arp_responder.h" +#include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_on_demand_engine.h" using namespace std; using namespace aca_vlan_manager; @@ -326,7 +329,9 @@ void ACA_On_Demand_Engine::on_demand(string uuid_for_call, OperationStatus statu ch++; } options = inport + whitespace + packetpre + serialized_packet + whitespace + action; - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out( + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out( + // bridge.c_str(), options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out( bridge.c_str(), options.c_str()); ACA_LOG_DEBUG("On-demand packet with protocol %d sent to ovs: %s\n", protocol, options.c_str()); diff --git a/src/ovs/aca_arp_responder.cpp b/src/ovs/aca_arp_responder.cpp index 9e81e0fb..f2a2b4ae 100644 --- a/src/ovs/aca_arp_responder.cpp +++ b/src/ovs/aca_arp_responder.cpp @@ -258,8 +258,10 @@ void ACA_ARP_Responder::arp_xmit(uint32_t in_port, void *vlanmsg, void *message, } ACA_LOG_DEBUG("ACA_ARP_Responder sent arp packet to ovs: %s\n", options.c_str()); - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), - options.c_str()); + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), + // options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out(bridge.c_str(), + options.c_str()); } int ACA_ARP_Responder::_parse_arp_request(uint32_t in_port, vlan_message *vlanmsg, diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index 617b0b1c..a3e6d6b2 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -295,6 +295,40 @@ int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, con return rc; } +std::unordered_map ACA_OVS_L2_Programmer::get_system_port_ids() +{ + // these 2 system ports belong to br-tun + const string patch_int_port = "patch-int"; + const string vxlan_generic_port = "vxlan-generic"; + std::unordered_map port_id_map; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::get_system_port_ids ---> Entering\n"); + auto ovsdb_client_start = chrono::steady_clock::now(); + + string patch_int_ofport_query = "ovs-vsctl get Interface " + patch_int_port + " ofport"; + string patch_int_ofport_id = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(patch_int_ofport_query); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids - adding %s - %s mapping to port_id_map\n", patch_int_port.c_str(), patch_int_ofport_id.c_str()); + port_id_map[patch_int_port] = patch_int_ofport_id; + + string vxlan_ofport_query = "ovs-vsctl get Interface " + vxlan_generic_port + " ofport"; + string vxlan_ofport_id = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(vxlan_ofport_query); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids - adding %s - %s mapping to port_id_map\n", vxlan_generic_port.c_str(), vxlan_ofport_id.c_str()); + port_id_map[vxlan_generic_port] = vxlan_ofport_id; + + auto ovsdb_client_end = chrono::steady_clock::now(); + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::get_system_port_ids - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids <--- Exiting\n"); + + return port_id_map; +} + std::unordered_map ACA_OVS_L2_Programmer::get_ovs_bridge_mapping() { const string br_int_str = "br-int"; @@ -321,7 +355,6 @@ std::unordered_map ACA_OVS_L2_Programmer::get_ovs_bridge_ switch_dpid_map[br_tun_dpid] = br_tun_str; auto ovsdb_client_end = chrono::steady_clock::now(); - auto ovsdb_client_time_total_time = cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); @@ -610,4 +643,28 @@ void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Exiting\n"); } +void ACA_OVS_L2_Programmer::packet_out(const char *bridge, const char *options) +{ + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Entering\n"); + auto openflow_client_start = chrono::steady_clock::now(); + + if (NULL != ofctrl) { + ofctrl->packet_out(bridge, options); + } else { + ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::packet_out didn't find OF controller\n"); + } + + auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Exiting\n"); +} + } // namespace aca_ovs_l2_programmer diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index 02836f6d..2195447c 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -3,6 +3,7 @@ #include "of_controller.h" #include "aca_log.h" #include "aca_util.h" +#include "aca_on_demand_engine.h" using namespace fluid_base; using namespace fluid_msg; @@ -47,6 +48,13 @@ void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* da } else if (type == fluid_msg::of13::OFPT_BARRIER_REPLY) { auto t = std::chrono::high_resolution_clock::now(); ACA_LOG_INFO("OFController::message_callback - recv OFPT_BARRIER_REPLY on %ld\n", t.time_since_epoch().count()); + } else if (type == fluid_msg::of13::OFPT_PACKET_IN) { + fluid_msg::of13::PacketIn *pin = new of13::PacketIn(); + pin->unpack((uint8_t *) data); + uint32_t in_port = pin->match().in_port()->value(); + + // pass new allocated memory of packet-in to ACA_On_Demand_Engine to determine which type of request it is + aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().parse_packet(in_port, (void*)pin->data()); } else if (type == 33) { // OFPRAW_OFPT14_BUNDLE_CONTROL auto t = std::chrono::high_resolution_clock::now(); @@ -140,7 +148,7 @@ void OFController::remove_switch_from_conn_map(int ofconn_id) { ofconn_id); } -void OFController::send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p) { +void OFController::send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p) { p->set_xid(xid.fetch_add(1)); auto buf = p->pack(); @@ -151,6 +159,14 @@ void OFController::send_packet(OFConnection *ofconn, ofmsg_ptr_t &&p) { ofconn->send(buf->data(), buf->len()); } +void OFController::send_packet_out(OFConnection *ofconn, OFRawBuf* po) { + if (!po) { + return; + } + + ofconn->send(po->data(), po->len()); +} + void OFController::send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods) { xid.fetch_add(1); BundleFlowModMessage bundle(flow_mods, &xid); @@ -175,14 +191,14 @@ void OFController::setup_default_flows() { OFConnection* ofconn_br_tun = get_instance("br-tun"); if (NULL != ofconn_br_tun) { - send_packet(ofconn_br_tun, create_add_flow("table=0,priority=50,arp,arp_op=1, actions=CONTROLLER")); - send_packet(ofconn_br_tun, create_add_flow("table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)")); - send_packet(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)")); - send_packet(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)")); - send_packet(ofconn_br_tun, create_add_flow("table=20,priority=1 actions=CONTROLLER")); - send_packet(ofconn_br_tun, create_add_flow("table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)")); - send_packet(ofconn_br_tun, create_add_flow("table=52,priority=1 actions=resubmit(,20)")); - send_packet(ofconn_br_tun, create_add_flow("table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=50,arp,arp_op=1, actions=CONTROLLER")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=1,in_port=" + port_id_map["patch-int"] + " actions=resubmit(,2)")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)")); + send_flow(ofconn_br_tun, create_add_flow("table=20,priority=1 actions=CONTROLLER")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=25,icmp,icmp_type=8,in_port=" + port_id_map["patch-int"] + " actions=resubmit(,52)")); + send_flow(ofconn_br_tun, create_add_flow("table=52,priority=1 actions=resubmit(,20)")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=25,in_port=" + port_id_map["vxlan-generic"] + " actions=resubmit(,4)")); } else { ACA_LOG_ERROR("OFController::setup_default_flows - ovs connection of br-tun not found\n"); } @@ -195,18 +211,30 @@ void OFController::execute_flow(const std::string br, const std::string flow_str if (NULL != ofconn_br) { if (action == "add") { - send_packet(ofconn_br, create_add_flow(flow_str)); + send_flow(ofconn_br, create_add_flow(flow_str)); } else if (action == "mod") { // --strict mod - send_packet(ofconn_br, create_mod_flow(flow_str, true)); + send_flow(ofconn_br, create_mod_flow(flow_str, true)); } else if (action == "del") { // --strict del - send_packet(ofconn_br, create_del_flow(flow_str, true)); + send_flow(ofconn_br, create_del_flow(flow_str, true)); } else { ACA_LOG_ERROR("OFController::execute_flow - action %s not supported in flow %s\n", action.c_str(), flow_str.c_str()); } } else { - ACA_LOG_ERROR("OFController::execute_flow - ovs connection of br-tun not found\n"); + ACA_LOG_ERROR("OFController::execute_flow - ovs connection to bridge %s not found\n", br.c_str()); + } + + ofconn_br = NULL; +} + +void OFController::packet_out(const char* br, const char* opt) { + OFConnection* ofconn_br = get_instance(std::string(br)); + + if (NULL != ofconn_br) { + send_packet_out(ofconn_br, create_packet_out(br, opt)); + } else { + ACA_LOG_ERROR("OFController::packet_out - ovs connection to bridge %s not found\n", br); } ofconn_br = NULL; diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp index 88745966..f65c207b 100644 --- a/src/ovs/of_message.cpp +++ b/src/ovs/of_message.cpp @@ -259,8 +259,7 @@ ofmsg_ptr_t create_del_flow(const std::string& flow, bool strict) { return std::make_shared(op_type, flow); } -std::vector create_add_flows(const std::vector& flows) -{ +std::vector create_add_flows(const std::vector& flows) { std::vector ret; for (const auto &flow : flows) { ret.emplace_back(std::make_shared(ADD_FLOW, flow)); @@ -268,3 +267,24 @@ std::vector create_add_flows(const std::vector& flows) return ret; } + +OFRawBuf* create_packet_out(const char* bridge, const char* option) { + enum ofputil_protocol usable_protocols; + struct ofputil_packet_out po; + + struct ofpbuf *opo; + char *error; + + error = parse_ofp_packet_out_str(&po, option, NULL, &usable_protocols); + if (error) { + ACA_LOG_ERROR("OFMessage - create_packet_out had error %s\n", error); + } + + opo = ofputil_encode_packet_out(&po, DEFAULT_OF_VERSION); + OFPBuf* buf = new OFPBuf(opo); + + free(CONST_CAST(void *, po.packet)); + free(po.ofpacts); + + return (OFRawBuf*)buf; +} \ No newline at end of file From 92b4cab0796ca22074dd2a3fa1a7e720299d4d1f Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 2 Sep 2021 11:01:31 -0700 Subject: [PATCH 14/54] Leverage smart pointer to avoid memory leak --- include/of_controller.h | 2 +- include/of_message.h | 3 ++- src/ovs/of_controller.cpp | 4 ++-- src/ovs/of_message.cpp | 26 ++++++++++---------------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/include/of_controller.h b/include/of_controller.h index bbebd0d4..ab81f2e0 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -87,7 +87,7 @@ class OFController : public OFServer { void send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p); - void send_packet_out(OFConnection *ofconn, OFRawBuf* po); + void send_packet_out(OFConnection *ofconn, ofbuf_ptr_t &&po); void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); }; diff --git a/include/of_message.h b/include/of_message.h index 75cb129f..fcc07ce9 100644 --- a/include/of_message.h +++ b/include/of_message.h @@ -24,6 +24,7 @@ class OFMessage { typedef uint32_t ofmsg_xid_t; typedef std::shared_ptr ofmsg_ptr_t; +typedef std::shared_ptr ofbuf_ptr_t; class BundleFlowModMessage { public: @@ -77,4 +78,4 @@ ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle = false); ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict); ofmsg_ptr_t create_del_flow(const std::string& match, bool strict); std::vector create_add_flows(const std::vector& flows, bool bundle = false); -OFRawBuf* create_packet_out(const char* bridge, const char* option); \ No newline at end of file +ofbuf_ptr_t create_packet_out(const char* option); \ No newline at end of file diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index 2195447c..f880686a 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -159,7 +159,7 @@ void OFController::send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p) { ofconn->send(buf->data(), buf->len()); } -void OFController::send_packet_out(OFConnection *ofconn, OFRawBuf* po) { +void OFController::send_packet_out(OFConnection *ofconn, ofbuf_ptr_t &&po) { if (!po) { return; } @@ -232,7 +232,7 @@ void OFController::packet_out(const char* br, const char* opt) { OFConnection* ofconn_br = get_instance(std::string(br)); if (NULL != ofconn_br) { - send_packet_out(ofconn_br, create_packet_out(br, opt)); + send_packet_out(ofconn_br, create_packet_out(opt)); } else { ACA_LOG_ERROR("OFController::packet_out - ovs connection to bridge %s not found\n", br); } diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp index f65c207b..267b86b4 100644 --- a/src/ovs/of_message.cpp +++ b/src/ovs/of_message.cpp @@ -62,7 +62,7 @@ class OFBaseMessage : public OFMessage { _xid = id; } - std::shared_ptr pack_ofpbuf(struct ofpbuf* buf) { + ofbuf_ptr_t pack_ofpbuf(struct ofpbuf* buf) { auto header = static_cast(buf->data); header->xid = htonl(_xid); @@ -91,7 +91,7 @@ class FlowModMessage : public OFBaseMessage { ~FlowModMessage() override = default; - std::shared_ptr pack() override { + ofbuf_ptr_t pack() override { int command = OFPFC_ADD; std::string cmd_str = "ADD"; @@ -160,7 +160,7 @@ class FlowModMessage : public OFBaseMessage { //OFPact ofpacts(fm.ofpacts); free(CONST_CAST(struct ofpact *, fm.ofpacts)); - return pack_ofpbuf(buf); + return std::make_shared(buf); } private: @@ -169,7 +169,7 @@ class FlowModMessage : public OFBaseMessage { enum ofputil_protocol _of_ver; }; -std::shared_ptr BundleFlowModMessage::pack_open_req() { +ofbuf_ptr_t BundleFlowModMessage::pack_open_req() { struct ofputil_bundle_ctrl_msg bundle_ctrl; // needs to handshake OFPBCT_OPEN_REQUEST first for ovs to get ready for the following bundle bundle_ctrl.type = OFPBCT_OPEN_REQUEST; @@ -189,7 +189,7 @@ std::shared_ptr BundleFlowModMessage::pack_open_req() { return std::make_shared(buf); } -std::shared_ptr BundleFlowModMessage::pack_commit_req() { +ofbuf_ptr_t BundleFlowModMessage::pack_commit_req() { struct ofputil_bundle_ctrl_msg bundle_ctrl; // bundle_id has to be consistent with open request bundle_ctrl.bundle_id = _bundle_id; @@ -205,8 +205,8 @@ std::shared_ptr BundleFlowModMessage::pack_commit_req() { return std::make_shared(buf); } -std::vector > BundleFlowModMessage::pack_flow_mods() { - std::vector > ret_buf; +std::vector BundleFlowModMessage::pack_flow_mods() { + std::vector ret_buf; for (auto of_msg : _flow_mods) { struct ofputil_bundle_add_msg bundle_flow_mod; @@ -268,11 +268,9 @@ std::vector create_add_flows(const std::vector& flows) return ret; } -OFRawBuf* create_packet_out(const char* bridge, const char* option) { +ofbuf_ptr_t create_packet_out(const char* option) { enum ofputil_protocol usable_protocols; struct ofputil_packet_out po; - - struct ofpbuf *opo; char *error; error = parse_ofp_packet_out_str(&po, option, NULL, &usable_protocols); @@ -280,11 +278,7 @@ OFRawBuf* create_packet_out(const char* bridge, const char* option) { ACA_LOG_ERROR("OFMessage - create_packet_out had error %s\n", error); } - opo = ofputil_encode_packet_out(&po, DEFAULT_OF_VERSION); - OFPBuf* buf = new OFPBuf(opo); + auto buf = ofputil_encode_packet_out(&po, DEFAULT_OF_VERSION); - free(CONST_CAST(void *, po.packet)); - free(po.ofpacts); - - return (OFRawBuf*)buf; + return std::make_shared(buf); } \ No newline at end of file From e1bb6903fefb2fa253fc054c8a76122362d22915 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 2 Sep 2021 13:27:06 -0700 Subject: [PATCH 15/54] Fix aca_vlan_manager output of_port number --- include/aca_ovs_l2_programmer.h | 3 +++ src/ovs/aca_ovs_l2_programmer.cpp | 38 ++++++++++++++++--------------- src/ovs/aca_vlan_manager.cpp | 3 ++- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index 80e1054e..e8535695 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -38,6 +38,8 @@ class ACA_OVS_L2_Programmer { std::unordered_map get_system_port_ids(); + std::string get_system_port_id(std::string port_name); + bool is_ip_on_the_same_host(const std::string hosting_port_ip); int setup_ovs_bridges_if_need(); @@ -81,6 +83,7 @@ class ACA_OVS_L2_Programmer { private: OFController* ofctrl; + std::unordered_map port_id_map; ACA_OVS_L2_Programmer(){}; ~ACA_OVS_L2_Programmer(){}; diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index a3e6d6b2..c1f9df12 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -221,8 +221,6 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() " type=vxlan options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:remote_ip=flow", not_care_culminative_time, overall_rc); - execute_openflow_command("add-flow br-tun \"table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)\"", - not_care_culminative_time, overall_rc); setup_ovs_bridges_mutex.unlock(); // -----critical section ends----- @@ -295,12 +293,16 @@ int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, con return rc; } +std::string ACA_OVS_L2_Programmer::get_system_port_id(std::string port_name) +{ + return port_id_map[port_name]; +} + std::unordered_map ACA_OVS_L2_Programmer::get_system_port_ids() { // these 2 system ports belong to br-tun const string patch_int_port = "patch-int"; const string vxlan_generic_port = "vxlan-generic"; - std::unordered_map port_id_map; ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::get_system_port_ids ---> Entering\n"); auto ovsdb_client_start = chrono::steady_clock::now(); @@ -645,26 +647,26 @@ void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, void ACA_OVS_L2_Programmer::packet_out(const char *bridge, const char *options) { - ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Entering\n"); - auto openflow_client_start = chrono::steady_clock::now(); + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Entering\n"); + auto openflow_client_start = chrono::steady_clock::now(); - if (NULL != ofctrl) { - ofctrl->packet_out(bridge, options); - } else { - ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::packet_out didn't find OF controller\n"); - } + if (NULL != ofctrl) { + ofctrl->packet_out(bridge, options); + } else { + ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::packet_out didn't find OF controller\n"); + } - auto openflow_client_end = chrono::steady_clock::now(); - auto openflow_client_time_total_time = - cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); - g_total_execute_openflow_time += openflow_client_time_total_time; + g_total_execute_openflow_time += openflow_client_time_total_time; - ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time)); + ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); - ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Exiting\n"); + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Exiting\n"); } } // namespace aca_ovs_l2_programmer diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index 377a905c..12f85a9f 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -123,10 +123,11 @@ int ACA_Vlan_Manager::create_ovs_port(string /*vpc_id*/, string ovs_port, // to stamp with internal vlan and deliver to br-int if (current_vpc_table_entry->ovs_ports.empty()) { int internal_vlan_id = current_vpc_table_entry->vlan_id; + string patch_int_port_id = ACA_OVS_L2_Programmer::get_instance().get_system_port_id("patch-int"); string cmd_string = "table=4, priority=1,tun_id=" + to_string(tunnel_id) + - " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:\"patch-int\""; + " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:" + patch_int_port_id; ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, "br-tun", From 8b9c1132fec697b6ace1187e26279ecf55a25106 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 2 Sep 2021 14:40:36 -0700 Subject: [PATCH 16/54] Fix default allow flows for both br-int and br-tun --- include/of_controller.h | 4 +++- src/ovs/of_controller.cpp | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/of_controller.h b/include/of_controller.h index ab81f2e0..47dae1ea 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -61,7 +61,9 @@ class OFController : public OFServer { void remove_switch_from_conn_map(int ofconn_id); - void setup_default_flows(); + void setup_default_br_int_flows(); + + void setup_default_br_tun_flows(); void execute_flow(const std::string br, const std::string flow_str, const std::string action = "add"); diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index f880686a..b45bd031 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -40,9 +40,13 @@ void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* da std::string bridge_name = switch_dpid_map[dpid]; add_switch_to_conn_map(bridge_name, ofconn->get_id(), ofconn); - // when br-tun is connected, setup default flow + // setup default flows for each bridge + if (bridge_name == "br-int") { + setup_default_br_int_flows(); + } + if (bridge_name == "br-tun") { - setup_default_flows(); + setup_default_br_tun_flows(); } } } else if (type == fluid_msg::of13::OFPT_BARRIER_REPLY) { @@ -186,11 +190,23 @@ void OFController::send_bundle_flow_mods(OFConnection *ofconn, std::vectorget_id(), bundle.get_bundle_id()); } -void OFController::setup_default_flows() { - // all default flows are added to 'br-tun' only +void OFController::setup_default_br_int_flows() { + OFConnection* ofconn_br_int = get_instance("br-int"); + + if (NULL != ofconn_br_int) { + send_flow(ofconn_br_int, create_add_flow("table=0,priority=0, actions=NORMAL")); + } else { + ACA_LOG_ERROR("OFController::setup_default_br_int_flows - ovs connection not found\n"); + } + + ofconn_br_int = NULL; +} + +void OFController::setup_default_br_tun_flows() { OFConnection* ofconn_br_tun = get_instance("br-tun"); if (NULL != ofconn_br_tun) { + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=0, actions=NORMAL")); send_flow(ofconn_br_tun, create_add_flow("table=0,priority=50,arp,arp_op=1, actions=CONTROLLER")); send_flow(ofconn_br_tun, create_add_flow("table=0,priority=1,in_port=" + port_id_map["patch-int"] + " actions=resubmit(,2)")); send_flow(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)")); @@ -200,7 +216,7 @@ void OFController::setup_default_flows() { send_flow(ofconn_br_tun, create_add_flow("table=52,priority=1 actions=resubmit(,20)")); send_flow(ofconn_br_tun, create_add_flow("table=0,priority=25,in_port=" + port_id_map["vxlan-generic"] + " actions=resubmit(,4)")); } else { - ACA_LOG_ERROR("OFController::setup_default_flows - ovs connection of br-tun not found\n"); + ACA_LOG_ERROR("OFController::setup_default_br_tun_flows - ovs connection not found\n"); } ofconn_br_tun = NULL; From 7d5ef1c50074af34a4f29169f01d5befec09f750 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 2 Sep 2021 15:10:40 -0700 Subject: [PATCH 17/54] Fix missing L2 neighbor rule --- src/aca_main.cpp | 6 ++++-- src/ovs/aca_vlan_manager.cpp | 23 ++++++++--------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/aca_main.cpp b/src/aca_main.cpp index e5a37788..afaf58af 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -313,8 +313,10 @@ int main(int argc, char *argv[]) //// monitor br-tun for arp request message //ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); - ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); - rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + //ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); + //rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + + pause(); aca_cleanup(); return rc; diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index 12f85a9f..99721f75 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -180,14 +180,11 @@ int ACA_Vlan_Manager::delete_ovs_port(string /*vpc_id*/, string ovs_port, int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, string remote_host_ip, uint tunnel_id, - ulong & /*culminative_time*/) + ulong & culminative_time) { ACA_LOG_DEBUG("%s", "ACA_Vlan_Manager::create_l2_neighbor ---> Entering\n"); - int overall_rc; - int internal_vlan_id = get_or_create_vlan_id(tunnel_id); - arp_config stArpCfg; // match internal vlan based on VPC and destination neighbor mac, @@ -199,30 +196,26 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, string action_string = ",actions=strip_vlan,load:" + to_string(tunnel_id) + "->NXM_NX_TUN_ID[],set_field:" + remote_host_ip + "->tun_dst,output:" + VXLAN_GENERIC_OUTPORT_NUMBER; - std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); - /* - overall_rc = ACA_OVS_Control::get_instance().add_flow( - "br-tun", (match_string + action_string).c_str()); + std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + match_string + action_string, + "add"); std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); + auto message_total_operation_time = std::chrono::duration_cast(end - start).count(); ACA_LOG_DEBUG("[create_l2_neighbor] Start adding ovs rule at: [%ld], finished at: [%ld]\nElapsed time for adding ovs rule for l2 neighbor took: %ld microseconds or %ld milliseconds\n", start, end, message_total_operation_time, (message_total_operation_time / 1000)); - if (overall_rc != EXIT_SUCCESS) { - ACA_LOG_ERROR("%s", "Failed to add L2 neighbor rule\n"); - }; - */ - - // create arp entry in arp responder for the l2 neighbor stArpCfg.mac_address = virtual_mac; stArpCfg.ipv4_address = virtual_ip; stArpCfg.vlan_id = internal_vlan_id; - ACA_ARP_Responder::get_instance().create_or_update_arp_entry(&stArpCfg); + overall_rc = ACA_ARP_Responder::get_instance().create_or_update_arp_entry(&stArpCfg); ACA_LOG_DEBUG("create_l2_neighbor arp entry with ip = %s, vlan id = %u and mac = %s\n", virtual_ip.c_str(), internal_vlan_id, virtual_mac.c_str()); From 77301cdde06b6bf5c9d1fd83e10da496a65f18b0 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 2 Sep 2021 15:56:23 -0700 Subject: [PATCH 18/54] Pass packet-in event processing to on-demand-engine thread pool for better performance --- src/ovs/of_controller.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index b45bd031..737fe919 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -58,7 +58,10 @@ void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* da uint32_t in_port = pin->match().in_port()->value(); // pass new allocated memory of packet-in to ACA_On_Demand_Engine to determine which type of request it is - aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().parse_packet(in_port, (void*)pin->data()); + aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().thread_pool_.push( + std::bind(&aca_on_demand_engine::ACA_On_Demand_Engine::parse_packet, + &aca_on_demand_engine::ACA_On_Demand_Engine::get_instance(), + in_port, (void *)pin->data())); } else if (type == 33) { // OFPRAW_OFPT14_BUNDLE_CONTROL auto t = std::chrono::high_resolution_clock::now(); From ea57254735ad6c29b36cb5f667d4e976f1c153fd Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 3 Sep 2021 10:46:35 -0700 Subject: [PATCH 19/54] Add common dependencies installation in init sh --- build/aca-machine-init.sh | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 2399f284..7feb64d2 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -18,14 +18,23 @@ BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" # TODO: remove the unneeded dependencies -echo "1--- installing mizar dependencies ---" && \ +echo "1--- installing common dependencies ---" && \ apt-get update -y && apt-get install -y \ rpcbind \ rsyslog \ build-essential \ + make \ + g++ \ + unzip \ + cmake \ clang-9 \ llvm-9 \ libelf-dev \ + doxygen \ + zlib1g-dev \ + libssl-dev \ + libboost-program-options-dev \ + libboost-all-dev \ iproute2 \ net-tools \ iputils-ping \ @@ -35,7 +44,15 @@ echo "1--- installing mizar dependencies ---" && \ python3-pip \ netcat \ libcmocka-dev \ - lcov + lcov \ + git \ + autoconf \ + automake \ + dh-autoreconf \ + pkg-config \ + libtool \ + wget \ + uuid-dev pip3 install httpserver netaddr echo "2--- installing librdkafka ---" && \ From 29e6625a9c2e166eb376b4c2f125ab242e4652ce Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 3 Sep 2021 16:20:07 -0700 Subject: [PATCH 20/54] Fix init scripts for fresh runtime preparation --- build/Dockerfile | 2 ++ build/aca-machine-init.sh | 5 ++++- src/README.md | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index e8403e21..fda70e07 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -13,6 +13,8 @@ # 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. FROM fwnetworking/ubuntu:18.04 +RUN rm -rf /var/local/git && mkdir -p /var/local/git + RUN echo "1--- installing common dependencies ---" && \ apt-get update -y && apt-get install -y \ rpcbind \ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 7feb64d2..d11c3531 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -17,6 +17,9 @@ BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" +rm -rf /var/local/git +mkdir -p /var/local/git + # TODO: remove the unneeded dependencies echo "1--- installing common dependencies ---" && \ apt-get update -y && apt-get install -y \ @@ -204,7 +207,7 @@ echo "7--- installing pulsar dependacies ---" && \ echo "8--- building alcor-control-agent" cd $BUILD/.. && cmake . && make -if [ "$1" == "delete-bridges" ]; then +if [ -n "$1" -a "$1" = "delete-bridges" ]; then echo "9--- deleting br-tun and br-int if requested" PATH=$PATH:/usr/local/share/openvswitch/scripts \ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib diff --git a/src/README.md b/src/README.md index 8833e6c8..2ce1abc8 100644 --- a/src/README.md +++ b/src/README.md @@ -69,15 +69,15 @@ You will need approval from at least one maintainer, who will merge your codes t ## Run the build script to set up the build container and compile the alcor-control-agent Assuming alcor-control-agent was cloned into ~/alcor-control-agent directory: ```Shell -cd ~/alcor-control-agent -./build/build.sh +cd ~/alcor-control-agent/build +sudo ./build.sh ``` ## You can also setup a physical machine or VM to compile the alcor-control-agent Assuming alcor-control-agent was cloned into ~/alcor-control-agent directory: ```Shell -cd ~/alcor-control-agent -./build/aca-machine-init.sh +cd ~/alcor-control-agent/build +sudo ./aca-machine-init.sh ``` ## Running alcor-control-agent and tests From e135023091975a8ed7489b1d91da413519ea10c9 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 9 Sep 2021 12:21:07 -0700 Subject: [PATCH 21/54] Address code review feedbacks --- build/test.sh | 200 ------------------------------ include/aca_ovs_l2_programmer.h | 16 +-- src/aca_main.cpp | 34 +---- src/ovs/aca_ovs_l2_programmer.cpp | 35 ++++-- 4 files changed, 39 insertions(+), 246 deletions(-) delete mode 100644 build/test.sh diff --git a/build/test.sh b/build/test.sh deleted file mode 100644 index e9772ea9..00000000 --- a/build/test.sh +++ /dev/null @@ -1,200 +0,0 @@ -# MIT License -# Copyright(c) 2020 Futurewei Cloud -# -# Permission is hereby granted, -# free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. - -#!/bin/bash - -BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -echo "build path is $BUILD" - -# TODO: remove the unneeded dependencies -echo "1--- installing mizar dependencies ---" && \ - apt-get update -y && apt-get install -y \ - rpcbind \ - rsyslog \ - build-essential \ - clang-9 \ - llvm-9 \ - libelf-dev \ - iproute2 \ - net-tools \ - iputils-ping \ - ethtool \ - curl \ - python3 \ - python3-pip \ - netcat \ - libcmocka-dev \ - lcov -pip3 install httpserver netaddr - -echo "2--- installing librdkafka ---" && \ - apt-get update -y && apt-get install -y --no-install-recommends\ - librdkafka-dev \ - doxygen \ - libssl-dev \ - zlib1g-dev \ - libboost-program-options-dev \ - libboost-all-dev \ - && apt-get clean - -echo "3--- installing cppkafka ---" && \ - apt-get update -y && apt-get install -y cmake - git clone https://github.com/mfontanini/cppkafka.git /var/local/git/cppkafka && \ - cd /var/local/git/cppkafka && \ - mkdir build && \ - cd build && \ - cmake .. && \ - make && \ - make install && \ - ldconfig && \ - rm -rf /var/local/git/cppkafka - cd ~ - -echo "4--- installing grpc dependencies ---" && \ - apt-get update -y && apt-get install -y \ - cmake libssl-dev \ - autoconf git pkg-config \ - automake libtool make g++ unzip - -# installing grpc and its dependencies -GRPC_RELEASE_TAG="v1.24.x" -echo "5--- cloning grpc repo ---" && \ - git clone -b $GRPC_RELEASE_TAG https://github.com/grpc/grpc /var/local/git/grpc && \ - cd /var/local/git/grpc && \ - git submodule update --init && \ - echo "--- installing c-ares ---" && \ - cd /var/local/git/grpc/third_party/cares/cares && \ - git fetch origin && \ - git checkout cares-1_15_0 && \ - mkdir -p cmake/build && \ - cd cmake/build && \ - cmake -DCMAKE_BUILD_TYPE=Release ../.. && \ - make -j4 install && \ - cd ../../../../.. && \ - rm -rf third_party/cares/cares && \ - echo "--- installing protobuf ---" && \ - cd /var/local/git/grpc/third_party/protobuf && \ - mkdir -p cmake/build && \ - cd cmake/build && \ - cmake -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 install && \ - cd ../../../.. && \ - rm -rf third_party/protobuf && \ - echo "--- installing grpc ---" && \ - cd /var/local/git/grpc && \ - mkdir -p cmake/build && \ - cd cmake/build && \ - cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release ../.. && \ - make -j4 install && \ - echo "--- installing google test ---" && \ - cd /var/local/git/grpc/third_party/googletest && \ - cmake -Dgtest_build_samples=ON -DBUILD_SHARED_LIBS=ON . && \ - make && \ - make install && \ - rm -rf /var/local/git/grpc && \ - cd ~ - -OVS_RELEASE_TAG="branch-2.12" -OVS_INCLUDE_HEADERS = \ - include/openvswitch/compiler.h \ - include/openvswitch/dynamic-string.h \ - include/openvswitch/hmap.h \ - include/openvswitch/flow.h \ - include/openvswitch/geneve.h \ - include/openvswitch/json.h \ - include/openvswitch/list.h \ - include/openvswitch/netdev.h \ - include/openvswitch/match.h \ - include/openvswitch/meta-flow.h \ - include/openvswitch/ofpbuf.h \ - include/openvswitch/ofp-actions.h \ - include/openvswitch/ofp-ed-props.h \ - include/openvswitch/ofp-errors.h \ - include/openvswitch/ofp-msgs.h \ - include/openvswitch/ofp-parse.h \ - include/openvswitch/ofp-print.h \ - include/openvswitch/ofp-prop.h \ - include/openvswitch/ofp-util.h \ - include/openvswitch/packets.h \ - include/openvswitch/poll-loop.h \ - include/openvswitch/rconn.h \ - include/openvswitch/shash.h \ - include/openvswitch/thread.h \ - include/openvswitch/token-bucket.h \ - include/openvswitch/tun-metadata.h \ - include/openvswitch/type-props.h \ - include/openvswitch/types.h \ - include/openvswitch/util.h \ - include/openvswitch/uuid.h \ - include/openvswitch/version.h \ - include/openvswitch/vconn.h \ - include/openvswitch/vlog.h \ - include/openvswitch/nsh.h -OPENFLOW_HEADERS = \ - include/openflow/intel-ext.h \ - include/openflow/netronome-ext.h \ - include/openflow/nicira-ext.h \ - include/openflow/openflow-1.0.h \ - include/openflow/openflow-1.1.h \ - include/openflow/openflow-1.2.h \ - include/openflow/openflow-1.3.h \ - include/openflow/openflow-1.4.h \ - include/openflow/openflow-1.5.h \ - include/openflow/openflow-1.6.h \ - include/openflow/openflow-common.h \ - include/openflow/openflow.h -echo "6--- installing openvswitch dependancies ---" && \ - git clone -b $OVS_RELEASE_TAG https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ - cd /var/local/git/openvswitch && \ - ./boot.sh && \ - ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ - make && \ - make install && \ - cd /var/local/git/openvswitch && \ - wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ - tar -xvzf openvswitch-2.9.8.tar.gz && \ - cd openvswitch-2.9.8 && \ - ./configure && make && \ - cp /var/local/git/openvswitch/openvswitch-2.9.8/lib/vconn-provider.h /usr/local/include/openvswitch && \ - cp /var/local/git/openvswitch/include/openvswitch/namemap.h /usr/local/include/openvswitch && \ - cp $OVS_INCLUDE_HEADERS /usr/local/include/openvswitch && \ - cp $OPENFLOW_HEADERS /usr/local/include/openflow && \ - cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ - rm -rf /var/local/git/openvswitch && \ - test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ - cd ~ - -PULSAR_RELEASE_TAG='pulsar-2.6.1' -echo "7--- installing pulsar dependacies ---" && \ - mkdir -p /var/local/git/pulsar && \ - wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ - wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client-dev.deb -O /var/local/git/pulsar/apache-pulsar-client-dev.deb && \ - cd /var/local/git/pulsar && \ - apt install -y ./apache-pulsar-client*.deb && \ - rm -rf /var/local/git/pulsar - cd ~ - -echo "8--- building alcor-control-agent" -cd $BUILD/.. && cmake . && make - -if [ "$1" == "delete-bridges" ]; then - echo "9--- deleting br-tun and br-int if requested" - PATH=$PATH:/usr/local/share/openvswitch/scripts \ - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - ovs-ctl --system-id=random --delete-bridges restart -fi - -echo "10--- running alcor-control-agent" -# sends output to null device, but stderr to console -nohup $BUILD/bin/AlcorControlAgent -d > /dev/null 2>&1 & diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index e8535695..f8dc7a48 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -32,23 +32,17 @@ class ACA_OVS_L2_Programmer { public: static ACA_OVS_L2_Programmer &get_instance(); - std::vector host_ips_vector; - void get_local_host_ips(); - std::unordered_map get_system_port_ids(); - - std::string get_system_port_id(std::string port_name); - bool is_ip_on_the_same_host(const std::string hosting_port_ip); int setup_ovs_bridges_if_need(); int setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port); - void set_openflow_controller(OFController* ofctrl); + void clean_up_ovs_controller(); - std::unordered_map get_ovs_bridge_mapping(); + std::string get_system_port_id(std::string port_name); int create_port(const std::string vpc_id, const std::string port_name, const std::string virtual_ip, const std::string virtual_mac, @@ -84,9 +78,15 @@ class ACA_OVS_L2_Programmer { private: OFController* ofctrl; std::unordered_map port_id_map; + std::vector host_ips_vector; ACA_OVS_L2_Programmer(){}; + ~ACA_OVS_L2_Programmer(){}; + + std::unordered_map get_ovs_bridge_mapping(); + + std::unordered_map get_system_port_ids(); }; } // namespace aca_ovs_l2_programmer #endif // #ifndef ACA_OVS_L2_PROGRAMMER_H \ No newline at end of file diff --git a/src/aca_main.cpp b/src/aca_main.cpp index afaf58af..681e6cd4 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -54,8 +54,6 @@ using namespace std; // Global variables std::thread *g_grpc_server_thread = NULL; std::thread *g_grpc_client_thread = NULL; -//std::thread *ovs_monitor_brtun_thread = NULL; -//std::thread *ovs_monitor_brint_thread = NULL; GoalStateProvisionerAsyncServer *g_grpc_server = NULL; GoalStateProvisionerClientImpl *g_grpc_client = NULL; string g_broker_list = EMPTY_STRING; @@ -67,8 +65,6 @@ string g_ofctl_target = EMPTY_STRING; string g_ofctl_options = EMPTY_STRING; string g_ncm_address = EMPTY_STRING; string g_ncm_port = EMPTY_STRING; - -OFController *g_ovs_ctrl = NULL; string g_ovs_ctrl_address = "127.0.0.1"; int g_ovs_ctrl_port = 1234; @@ -124,7 +120,6 @@ static void aca_cleanup() // Stop sets a private variable running_ to False // The Dispatch checks the variable in a loop and stops when running is // no longer set to True. - if (g_grpc_server != NULL) { g_grpc_server->ShutDownServer(); delete g_grpc_server; @@ -142,7 +137,7 @@ static void aca_cleanup() ACA_LOG_ERROR("%s", "Unable to call delete, grpc server thread pointer is null.\n"); } - //stops the grpc client + // Stop the grpc client if (g_grpc_client != NULL) { delete g_grpc_client; g_grpc_client = NULL; @@ -159,14 +154,8 @@ static void aca_cleanup() ACA_LOG_ERROR("%s", "Unable to call delete, grpc client thread pointer is null.\n"); } - if (g_ovs_ctrl != NULL) { - g_ovs_ctrl->stop(); - delete g_ovs_ctrl; - g_ovs_ctrl = NULL; - ACA_LOG_INFO("%s", "Cleaned up ovs controller.\n"); - } else { - ACA_LOG_INFO("%s", "Unable to clean up ovs controller, since it is null.\n"); - } + // Stop the ovs controller and clean up + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().clean_up_ovs_controller(); ACA_LOG_CLOSE(); } @@ -286,24 +275,9 @@ int main(int argc, char *argv[]) return rc; } - // get bridge and dpid mappings from ovs - std::unordered_map switch_dpid_map = - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_ovs_bridge_mapping(); - - // get system port name and ofportid mappings from ovs - std::unordered_map port_id_map = - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_system_port_ids(); - - // set bridge controller will clean up flows + // setup ovs controller with server ip address and port number, will be used for openflow operations aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_controller(g_ovs_ctrl_address, g_ovs_ctrl_port); - // start local ovs server (openflow controller) - g_ovs_ctrl = new OFController(switch_dpid_map, port_id_map, g_ovs_ctrl_address.c_str(), g_ovs_ctrl_port); - g_ovs_ctrl->start(); - - // pass ovs_ctrl handle to l2 programmer - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().set_openflow_controller(g_ovs_ctrl); - //// monitor br-int for dhcp request message //ovs_monitor_brint_thread = // new thread(bind(&ACA_OVS_Control::monitor, diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index c1f9df12..f3d0ec01 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -93,11 +93,6 @@ ACA_OVS_L2_Programmer &ACA_OVS_L2_Programmer::get_instance() return instance; } -void ACA_OVS_L2_Programmer::set_openflow_controller(OFController* ofctrl) -{ - this->ofctrl = ofctrl; -} - bool ACA_OVS_L2_Programmer::is_ip_on_the_same_host(const std::string host_ip) { return std::find(this->host_ips_vector.begin(), this->host_ips_vector.end(), @@ -264,8 +259,15 @@ int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, con const string setup_br_tun_cmd = "set-controller " + br_tun_str + ctrler_endpoint; ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::setup_ovs_controller ---> Entering\n"); - auto ovsdb_client_start = chrono::steady_clock::now(); + // get bridge and dpid mappings from ovs + std::unordered_map switch_dpid_map = get_ovs_bridge_mapping(); + + // get system port name and ofportid mappings from ovs + std::unordered_map port_id_map = get_system_port_ids(); + + // set bridge controller will clean up flows + auto ovsdb_client_start = chrono::steady_clock::now(); string br_int_cmd_string = "ovs-vsctl " + setup_br_int_cmd; rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(br_int_cmd_string); if (rc != EXIT_SUCCESS) { @@ -279,20 +281,37 @@ int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, con } auto ovsdb_client_end = chrono::steady_clock::now(); - auto ovsdb_client_time_total_time = cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); - g_total_execute_ovsdb_time += ovsdb_client_time_total_time; ACA_LOG_INFO("ACA_OVS_L2_Programmer::setup_ovs_controller - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + // start local ovs server (openflow controller) + ofctrl = new OFController(switch_dpid_map, port_id_map, ctrler_ip.c_str(), ctrler_port); + ofctrl->start(); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::setup_ovs_controller <--- Exiting\n"); return rc; } +void ACA_OVS_L2_Programmer::clean_up_ovs_controller() +{ + if (ofctrl != NULL) + { + ofctrl->stop(); + delete ofctrl; + ofctrl = NULL; + ACA_LOG_INFO("%s", "ACA_OVS_L2_Programmer::clean_up_ovs_controller - cleaned up ovs controller.\n"); + } + else + { + ACA_LOG_INFO("%s", "ACA_OVS_L2_Programmer::clean_up_ovs_controller - unable to clean up ovs controller, since it is null.\n"); + } +} + std::string ACA_OVS_L2_Programmer::get_system_port_id(std::string port_name) { return port_id_map[port_name]; From 4934df2001b479d611e24259675d2b1905b251fd Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 9 Sep 2021 12:53:35 -0700 Subject: [PATCH 22/54] Fix environment setup script for Jenkins CI/CD run --- build/Dockerfile | 5 +++++ build/aca-machine-init.sh | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/build/Dockerfile b/build/Dockerfile index fda70e07..68b102ea 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -157,6 +157,11 @@ ENV OPENFLOW_HEADERS='include/openflow/intel-ext.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h ' RUN echo "5--- installing openvswitch dependancies ---" && \ + rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + apt-get install -y python2.7 && \ + wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + python2.7 /tmp/get-pip.py && \ + pip2 install six && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index d11c3531..4e7ab5e2 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -172,6 +172,11 @@ OPENFLOW_HEADERS="include/openflow/intel-ext.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h " echo "6--- installing openvswitch dependancies ---" && \ + rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + apt-get install -y python2.7 && \ + wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + python2.7 /tmp/get-pip.py && \ + pip2 install six && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ From 9d430e4c5196c8a96b439f54041affc0b73f7410 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 9 Sep 2021 13:02:44 -0700 Subject: [PATCH 23/54] Run shell commands from sudo --- build/Dockerfile | 10 +++++----- build/aca-machine-init.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 68b102ea..44834537 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -157,11 +157,11 @@ ENV OPENFLOW_HEADERS='include/openflow/intel-ext.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h ' RUN echo "5--- installing openvswitch dependancies ---" && \ - rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ - apt-get install -y python2.7 && \ - wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ - python2.7 /tmp/get-pip.py && \ - pip2 install six && \ + sudo rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + sudo apt-get install -y python2.7 && \ + sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + sudo python2.7 /tmp/get-pip.py && \ + sudo pip2 install six && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 4e7ab5e2..d97dc7c8 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -172,11 +172,11 @@ OPENFLOW_HEADERS="include/openflow/intel-ext.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h " echo "6--- installing openvswitch dependancies ---" && \ - rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ - apt-get install -y python2.7 && \ - wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ - python2.7 /tmp/get-pip.py && \ - pip2 install six && \ + sudo rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + sudo apt-get install -y python2.7 && \ + sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + sudo python2.7 /tmp/get-pip.py && \ + sudo pip2 install six && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ From 5a8854443d3a122479745a8ee93d3efca3c2b1ac Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 9 Sep 2021 13:05:19 -0700 Subject: [PATCH 24/54] Move bash to top of the file --- build/aca-machine-init.sh | 4 ++-- build/build.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index d97dc7c8..add7077c 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # MIT License # Copyright(c) 2020 Futurewei Cloud # @@ -12,8 +14,6 @@ # 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. -#!/bin/bash - BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" diff --git a/build/build.sh b/build/build.sh index dd263c89..bdfad4a8 100755 --- a/build/build.sh +++ b/build/build.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # MIT License # Copyright(c) 2020 Futurewei Cloud # @@ -12,8 +14,6 @@ # 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. -#!/bin/bash - BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" From 105aaf67722530156c2056164349f6275b88fb8b Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Thu, 9 Sep 2021 14:03:32 -0700 Subject: [PATCH 25/54] Fix docker file --- build/Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 44834537..68b102ea 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -157,11 +157,11 @@ ENV OPENFLOW_HEADERS='include/openflow/intel-ext.h \ include/openflow/openflow-common.h \ include/openflow/openflow.h ' RUN echo "5--- installing openvswitch dependancies ---" && \ - sudo rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ - sudo apt-get install -y python2.7 && \ - sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ - sudo python2.7 /tmp/get-pip.py && \ - sudo pip2 install six && \ + rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + apt-get install -y python2.7 && \ + wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + python2.7 /tmp/get-pip.py && \ + pip2 install six && \ apt-get install -y libevent-dev && \ mkdir -p /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ From 489db61c26015d663f1ce9220a9e57882edaded4 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 10 Sep 2021 16:17:44 -0700 Subject: [PATCH 26/54] Address license reference for included library and written files --- README.md | 1 + include/libfluid-base/OFClient.hh | 15 ++++++++ include/libfluid-base/OFConnection.hh | 15 ++++++++ include/libfluid-base/OFServer.hh | 15 ++++++++ include/libfluid-base/OFServerSettings.hh | 15 ++++++++ include/libfluid-base/TLS.hh | 15 ++++++++ include/libfluid-base/base/BaseOFClient.hh | 15 ++++++++ .../libfluid-base/base/BaseOFConnection.hh | 15 ++++++++ include/libfluid-base/base/BaseOFServer.hh | 15 ++++++++ include/libfluid-base/base/EventLoop.hh | 15 ++++++++ include/libfluid-msg/of10/of10action.hh | 15 ++++++++ include/libfluid-msg/of10/of10common.hh | 15 ++++++++ include/libfluid-msg/of10/of10match.hh | 15 ++++++++ include/libfluid-msg/of10msg.hh | 15 ++++++++ include/libfluid-msg/of13/of13action.hh | 15 ++++++++ include/libfluid-msg/of13/of13common.hh | 15 ++++++++ include/libfluid-msg/of13/of13instruction.hh | 15 ++++++++ include/libfluid-msg/of13/of13match.hh | 15 ++++++++ include/libfluid-msg/of13/of13meter.hh | 15 ++++++++ include/libfluid-msg/of13/openflow-13.h | 36 +++++++++++++++++++ include/libfluid-msg/of13msg.hh | 15 ++++++++ include/libfluid-msg/ofcommon/action.hh | 15 ++++++++ include/libfluid-msg/ofcommon/common.hh | 15 ++++++++ include/libfluid-msg/ofcommon/msg.hh | 15 ++++++++ .../libfluid-msg/ofcommon/openflow-common.hh | 15 ++++++++ include/libfluid-msg/util/ethaddr.hh | 15 ++++++++ include/libfluid-msg/util/ipaddr.hh | 15 ++++++++ include/of_controller.h | 14 ++++++++ include/of_message.h | 14 ++++++++ src/ovs/of_controller.cpp | 14 ++++++++ src/ovs/of_message.cpp | 14 ++++++++ 31 files changed, 468 insertions(+) diff --git a/README.md b/README.md index 6a766db1..0ad14b22 100644 --- a/README.md +++ b/README.md @@ -51,5 +51,6 @@ This main repository of Alcor Control Agent is organized as follows: ## Notes * ovs_control.h and ovs_control.cpp is based on https://github.com/openvswitch/ovs/blob/master/utilities/ovs-ofctl.c +* libfluid-base/*.h(*.cpp) and libfluid-msg/*.h(*.cpp) are based on https://github.com/OpenNetworkingFoundation/libfluid, the usage of derived class is based on https://github.com/OpenNetworkingFoundation/libfluid/tree/master/examples/controller * aca_grpc.cpp is based on https://github.com/grpc/grpc/blob/v1.30.0/examples/cpp/route_guide/route_guide_server.cc * HashMap.h and HashNode.h is based on https://github.com/kshk123/hashMap diff --git a/include/libfluid-base/OFClient.hh b/include/libfluid-base/OFClient.hh index 2aaa89d0..1efa894d 100644 --- a/include/libfluid-base/OFClient.hh +++ b/include/libfluid-base/OFClient.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + #pragma once #include "base/BaseOFConnection.hh" diff --git a/include/libfluid-base/OFConnection.hh b/include/libfluid-base/OFConnection.hh index 49c32d4c..29761353 100644 --- a/include/libfluid-base/OFConnection.hh +++ b/include/libfluid-base/OFConnection.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __OFCONNECTION_HH__ #define __OFCONNECTION_HH__ diff --git a/include/libfluid-base/OFServer.hh b/include/libfluid-base/OFServer.hh index c38c0f41..a3ef3c54 100644 --- a/include/libfluid-base/OFServer.hh +++ b/include/libfluid-base/OFServer.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __OFSERVER_HH__ #define __OFSERVER_HH__ diff --git a/include/libfluid-base/OFServerSettings.hh b/include/libfluid-base/OFServerSettings.hh index f2158251..6dafe3e5 100644 --- a/include/libfluid-base/OFServerSettings.hh +++ b/include/libfluid-base/OFServerSettings.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __OFSERVERSETTINGS_HH__ #define __OFSERVERSETTINGS_HH__ diff --git a/include/libfluid-base/TLS.hh b/include/libfluid-base/TLS.hh index a09dab99..6c8b3029 100644 --- a/include/libfluid-base/TLS.hh +++ b/include/libfluid-base/TLS.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file Functions for secure communication using SSL */ #ifndef __SSL_IMPL_HH__ #define __SSL_IMPL_HH__ diff --git a/include/libfluid-base/base/BaseOFClient.hh b/include/libfluid-base/base/BaseOFClient.hh index 21356b01..05c249c3 100644 --- a/include/libfluid-base/base/BaseOFClient.hh +++ b/include/libfluid-base/base/BaseOFClient.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + #pragma once #include diff --git a/include/libfluid-base/base/BaseOFConnection.hh b/include/libfluid-base/base/BaseOFConnection.hh index 62e8130b..77e77963 100644 --- a/include/libfluid-base/base/BaseOFConnection.hh +++ b/include/libfluid-base/base/BaseOFConnection.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __BASEOFCONNECTION_HH__ #define __BASEOFCONNECTION_HH__ diff --git a/include/libfluid-base/base/BaseOFServer.hh b/include/libfluid-base/base/BaseOFServer.hh index 2eece696..8c2ae061 100644 --- a/include/libfluid-base/base/BaseOFServer.hh +++ b/include/libfluid-base/base/BaseOFServer.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __BASEOFSERVER_HH__ #define __BASEOFSERVER_HH__ diff --git a/include/libfluid-base/base/EventLoop.hh b/include/libfluid-base/base/EventLoop.hh index d6f53177..f4b0eb72 100644 --- a/include/libfluid-base/base/EventLoop.hh +++ b/include/libfluid-base/base/EventLoop.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + /** @file */ #ifndef __EVENTLOOP_HH__ #define __EVENTLOOP_HH__ diff --git a/include/libfluid-msg/of10/of10action.hh b/include/libfluid-msg/of10/of10action.hh index f6a3270b..9d9803d2 100644 --- a/include/libfluid-msg/of10/of10action.hh +++ b/include/libfluid-msg/of10/of10action.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF10ACTION_H #define OF10ACTION_H diff --git a/include/libfluid-msg/of10/of10common.hh b/include/libfluid-msg/of10/of10common.hh index 1bfb6cd5..f6abd393 100644 --- a/include/libfluid-msg/of10/of10common.hh +++ b/include/libfluid-msg/of10/of10common.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF10OPENFLOW_COMMON_H #define OF10OPENFLOW_COMMON_H 1 diff --git a/include/libfluid-msg/of10/of10match.hh b/include/libfluid-msg/of10/of10match.hh index 24f638d2..b259976c 100644 --- a/include/libfluid-msg/of10/of10match.hh +++ b/include/libfluid-msg/of10/of10match.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF10OPENFLOW_MATCH_H #define OF10OPENFLOW_MATCH_H 1 diff --git a/include/libfluid-msg/of10msg.hh b/include/libfluid-msg/of10msg.hh index 2e26cc25..64518275 100644 --- a/include/libfluid-msg/of10msg.hh +++ b/include/libfluid-msg/of10msg.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF10MSG_H #define OF10MSG_H 1 diff --git a/include/libfluid-msg/of13/of13action.hh b/include/libfluid-msg/of13/of13action.hh index c4a4540c..df3ffaec 100644 --- a/include/libfluid-msg/of13/of13action.hh +++ b/include/libfluid-msg/of13/of13action.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF13ACTION_H #define OF13ACTION_H diff --git a/include/libfluid-msg/of13/of13common.hh b/include/libfluid-msg/of13/of13common.hh index 18f6ed45..da01a016 100644 --- a/include/libfluid-msg/of13/of13common.hh +++ b/include/libfluid-msg/of13/of13common.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF13OPENFLOW_COMMON_H #define OF13OPENFLOW_COMMON_H 1 diff --git a/include/libfluid-msg/of13/of13instruction.hh b/include/libfluid-msg/of13/of13instruction.hh index 2ba37385..b875f9c9 100644 --- a/include/libfluid-msg/of13/of13instruction.hh +++ b/include/libfluid-msg/of13/of13instruction.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OPENFLOW_INSTRUCTION_H #define OPENFLOW_INSTRUCTION_H diff --git a/include/libfluid-msg/of13/of13match.hh b/include/libfluid-msg/of13/of13match.hh index 13b252af..2ce5e5d1 100644 --- a/include/libfluid-msg/of13/of13match.hh +++ b/include/libfluid-msg/of13/of13match.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OPENFLOW_MATCH_H #define OPENFLOW_MATCH_H 1 diff --git a/include/libfluid-msg/of13/of13meter.hh b/include/libfluid-msg/of13/of13meter.hh index 7c25843d..57f85310 100644 --- a/include/libfluid-msg/of13/of13meter.hh +++ b/include/libfluid-msg/of13/of13meter.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OPENFLOW_METER_H #define OPENFLOW_METER_H diff --git a/include/libfluid-msg/of13/openflow-13.h b/include/libfluid-msg/of13/openflow-13.h index b7e315b4..177b534e 100644 --- a/include/libfluid-msg/of13/openflow-13.h +++ b/include/libfluid-msg/of13/openflow-13.h @@ -1,3 +1,39 @@ +/* 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_OPENFLOW13_H #define OPENFLOW_OPENFLOW13_H 1 diff --git a/include/libfluid-msg/of13msg.hh b/include/libfluid-msg/of13msg.hh index b56f8acd..d8aa47b3 100644 --- a/include/libfluid-msg/of13msg.hh +++ b/include/libfluid-msg/of13msg.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OF13MSG_H #define OF13MSG_H 1 diff --git a/include/libfluid-msg/ofcommon/action.hh b/include/libfluid-msg/ofcommon/action.hh index 5fb6376b..00fa0921 100644 --- a/include/libfluid-msg/ofcommon/action.hh +++ b/include/libfluid-msg/ofcommon/action.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 ACTION_H #define ACTION_H diff --git a/include/libfluid-msg/ofcommon/common.hh b/include/libfluid-msg/ofcommon/common.hh index 0244bf75..86b67c6a 100644 --- a/include/libfluid-msg/ofcommon/common.hh +++ b/include/libfluid-msg/ofcommon/common.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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. + #pragma once #include diff --git a/include/libfluid-msg/ofcommon/msg.hh b/include/libfluid-msg/ofcommon/msg.hh index 071b3d8f..ba307dfc 100644 --- a/include/libfluid-msg/ofcommon/msg.hh +++ b/include/libfluid-msg/ofcommon/msg.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 MSG_H #define MSG_H 1 diff --git a/include/libfluid-msg/ofcommon/openflow-common.hh b/include/libfluid-msg/ofcommon/openflow-common.hh index 30c4d132..7070517e 100644 --- a/include/libfluid-msg/ofcommon/openflow-common.hh +++ b/include/libfluid-msg/ofcommon/openflow-common.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 OPENFLOW_OPENFLOWCOMMON_H #define OPENFLOW_OPENFLOWCOMMON_H 1 diff --git a/include/libfluid-msg/util/ethaddr.hh b/include/libfluid-msg/util/ethaddr.hh index 6a9c3052..ee0ab695 100644 --- a/include/libfluid-msg/util/ethaddr.hh +++ b/include/libfluid-msg/util/ethaddr.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 __MACADDRESS_H__ #define __MACADDRESS_H__ diff --git a/include/libfluid-msg/util/ipaddr.hh b/include/libfluid-msg/util/ipaddr.hh index c2771615..2480dc58 100644 --- a/include/libfluid-msg/util/ipaddr.hh +++ b/include/libfluid-msg/util/ipaddr.hh @@ -1,3 +1,18 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2021 The Alcor Authors +// +// 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 __IPADDRESS_H__ #define __IPADDRESS_H__ diff --git a/include/of_controller.h b/include/of_controller.h index 47dae1ea..21147d70 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -1,3 +1,17 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + #pragma once #include "of_message.h" diff --git a/include/of_message.h b/include/of_message.h index fcc07ce9..583e3bca 100644 --- a/include/of_message.h +++ b/include/of_message.h @@ -1,3 +1,17 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + #pragma once #include #include diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index 737fe919..e7f9a079 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -1,3 +1,17 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + #include #include "of_controller.h" diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp index 267b86b4..408b739f 100644 --- a/src/ovs/of_message.cpp +++ b/src/ovs/of_message.cpp @@ -1,3 +1,17 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + #include "of_message.h" #include "aca_log.h" #include "aca_util.h" From bfa8c6a043ba59577182637dc6dc96f950762160 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 10 Sep 2021 16:30:58 -0700 Subject: [PATCH 27/54] Fix author --- include/libfluid-base/OFClient.hh | 2 +- include/libfluid-base/OFConnection.hh | 2 +- include/libfluid-base/OFServer.hh | 2 +- include/libfluid-base/OFServerSettings.hh | 2 +- include/libfluid-base/TLS.hh | 2 +- include/libfluid-base/base/BaseOFClient.hh | 2 +- include/libfluid-base/base/BaseOFConnection.hh | 2 +- include/libfluid-base/base/BaseOFServer.hh | 2 +- include/libfluid-base/base/EventLoop.hh | 2 +- include/libfluid-msg/of10/of10action.hh | 2 +- include/libfluid-msg/of10/of10common.hh | 2 +- include/libfluid-msg/of10/of10match.hh | 2 +- include/libfluid-msg/of10msg.hh | 2 +- include/libfluid-msg/of13/of13action.hh | 2 +- include/libfluid-msg/of13/of13common.hh | 2 +- include/libfluid-msg/of13/of13instruction.hh | 2 +- include/libfluid-msg/of13/of13match.hh | 2 +- include/libfluid-msg/of13/of13meter.hh | 2 +- include/libfluid-msg/of13msg.hh | 2 +- include/libfluid-msg/ofcommon/action.hh | 2 +- include/libfluid-msg/ofcommon/common.hh | 2 +- include/libfluid-msg/ofcommon/msg.hh | 2 +- include/libfluid-msg/ofcommon/openflow-common.hh | 2 +- include/libfluid-msg/util/ethaddr.hh | 2 +- include/libfluid-msg/util/ipaddr.hh | 2 +- include/ovs_control.h | 2 +- src/ovs/ovs_control.cpp | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/libfluid-base/OFClient.hh b/include/libfluid-base/OFClient.hh index 1efa894d..6a71761c 100644 --- a/include/libfluid-base/OFClient.hh +++ b/include/libfluid-base/OFClient.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/OFConnection.hh b/include/libfluid-base/OFConnection.hh index 29761353..a761b465 100644 --- a/include/libfluid-base/OFConnection.hh +++ b/include/libfluid-base/OFConnection.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/OFServer.hh b/include/libfluid-base/OFServer.hh index a3ef3c54..531b26ef 100644 --- a/include/libfluid-base/OFServer.hh +++ b/include/libfluid-base/OFServer.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/OFServerSettings.hh b/include/libfluid-base/OFServerSettings.hh index 6dafe3e5..6a80c20f 100644 --- a/include/libfluid-base/OFServerSettings.hh +++ b/include/libfluid-base/OFServerSettings.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/TLS.hh b/include/libfluid-base/TLS.hh index 6c8b3029..168ee0d2 100644 --- a/include/libfluid-base/TLS.hh +++ b/include/libfluid-base/TLS.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/base/BaseOFClient.hh b/include/libfluid-base/base/BaseOFClient.hh index 05c249c3..6d3f312e 100644 --- a/include/libfluid-base/base/BaseOFClient.hh +++ b/include/libfluid-base/base/BaseOFClient.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/base/BaseOFConnection.hh b/include/libfluid-base/base/BaseOFConnection.hh index 77e77963..d9e1e65a 100644 --- a/include/libfluid-base/base/BaseOFConnection.hh +++ b/include/libfluid-base/base/BaseOFConnection.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/base/BaseOFServer.hh b/include/libfluid-base/base/BaseOFServer.hh index 8c2ae061..5377b154 100644 --- a/include/libfluid-base/base/BaseOFServer.hh +++ b/include/libfluid-base/base/BaseOFServer.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-base/base/EventLoop.hh b/include/libfluid-base/base/EventLoop.hh index f4b0eb72..8b8e9eb4 100644 --- a/include/libfluid-base/base/EventLoop.hh +++ b/include/libfluid-base/base/EventLoop.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of10/of10action.hh b/include/libfluid-msg/of10/of10action.hh index 9d9803d2..d036972d 100644 --- a/include/libfluid-msg/of10/of10action.hh +++ b/include/libfluid-msg/of10/of10action.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of10/of10common.hh b/include/libfluid-msg/of10/of10common.hh index f6abd393..6191a018 100644 --- a/include/libfluid-msg/of10/of10common.hh +++ b/include/libfluid-msg/of10/of10common.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of10/of10match.hh b/include/libfluid-msg/of10/of10match.hh index b259976c..54b518e6 100644 --- a/include/libfluid-msg/of10/of10match.hh +++ b/include/libfluid-msg/of10/of10match.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of10msg.hh b/include/libfluid-msg/of10msg.hh index 64518275..ce2176b3 100644 --- a/include/libfluid-msg/of10msg.hh +++ b/include/libfluid-msg/of10msg.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13/of13action.hh b/include/libfluid-msg/of13/of13action.hh index df3ffaec..5ea63717 100644 --- a/include/libfluid-msg/of13/of13action.hh +++ b/include/libfluid-msg/of13/of13action.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13/of13common.hh b/include/libfluid-msg/of13/of13common.hh index da01a016..75abe88b 100644 --- a/include/libfluid-msg/of13/of13common.hh +++ b/include/libfluid-msg/of13/of13common.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13/of13instruction.hh b/include/libfluid-msg/of13/of13instruction.hh index b875f9c9..a7dfdcdb 100644 --- a/include/libfluid-msg/of13/of13instruction.hh +++ b/include/libfluid-msg/of13/of13instruction.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13/of13match.hh b/include/libfluid-msg/of13/of13match.hh index 2ce5e5d1..f02cde8e 100644 --- a/include/libfluid-msg/of13/of13match.hh +++ b/include/libfluid-msg/of13/of13match.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13/of13meter.hh b/include/libfluid-msg/of13/of13meter.hh index 57f85310..c1ba6d8a 100644 --- a/include/libfluid-msg/of13/of13meter.hh +++ b/include/libfluid-msg/of13/of13meter.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/of13msg.hh b/include/libfluid-msg/of13msg.hh index d8aa47b3..d2839d22 100644 --- a/include/libfluid-msg/of13msg.hh +++ b/include/libfluid-msg/of13msg.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/ofcommon/action.hh b/include/libfluid-msg/ofcommon/action.hh index 00fa0921..7094f6c9 100644 --- a/include/libfluid-msg/ofcommon/action.hh +++ b/include/libfluid-msg/ofcommon/action.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/ofcommon/common.hh b/include/libfluid-msg/ofcommon/common.hh index 86b67c6a..e3510782 100644 --- a/include/libfluid-msg/ofcommon/common.hh +++ b/include/libfluid-msg/ofcommon/common.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/ofcommon/msg.hh b/include/libfluid-msg/ofcommon/msg.hh index ba307dfc..24ca84ff 100644 --- a/include/libfluid-msg/ofcommon/msg.hh +++ b/include/libfluid-msg/ofcommon/msg.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/ofcommon/openflow-common.hh b/include/libfluid-msg/ofcommon/openflow-common.hh index 7070517e..a8a773f8 100644 --- a/include/libfluid-msg/ofcommon/openflow-common.hh +++ b/include/libfluid-msg/ofcommon/openflow-common.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/util/ethaddr.hh b/include/libfluid-msg/util/ethaddr.hh index ee0ab695..0080fc52 100644 --- a/include/libfluid-msg/util/ethaddr.hh +++ b/include/libfluid-msg/util/ethaddr.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/libfluid-msg/util/ipaddr.hh b/include/libfluid-msg/util/ipaddr.hh index 2480dc58..df99407a 100644 --- a/include/libfluid-msg/util/ipaddr.hh +++ b/include/libfluid-msg/util/ipaddr.hh @@ -1,5 +1,5 @@ // Copyright (c) 2014 Open Networking Foundation -// Copyright 2021 The Alcor Authors +// Copyright 2020 Futurewei Cloud // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/include/ovs_control.h b/include/ovs_control.h index 2eb4d894..c0694e1f 100644 --- a/include/ovs_control.h +++ b/include/ovs_control.h @@ -1,5 +1,5 @@ // Copyright (c) 2008-2017, 2019 Nicira, Inc. -// Copyright 2019 The Alcor Authors - file modified. +// Copyright 2020 Futurewei Cloud - file modified. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/ovs/ovs_control.cpp b/src/ovs/ovs_control.cpp index a05fa595..8b529db0 100644 --- a/src/ovs/ovs_control.cpp +++ b/src/ovs/ovs_control.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2008-2017, 2019 Nicira, Inc. -// Copyright 2019 The Alcor Authors - file modified. +// Copyright 2020 Futurewei Cloud - file modified. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From ad87fabf550353fd8ca0fef638e8d0690c3f2a59 Mon Sep 17 00:00:00 2001 From: Longzhang Fu Date: Fri, 10 Sep 2021 16:44:34 -0700 Subject: [PATCH 28/54] Revert debug mode --- src/aca_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 681e6cd4..e599dc4a 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -80,7 +80,7 @@ std::atomic_ulong g_total_vpcs_table_mutex_time(0); std::atomic_ulong g_total_update_GS_time(0); bool g_demo_mode = false; -bool g_debug_mode = true; +bool g_debug_mode = false; int processor_count = std::thread::hardware_concurrency(); /* From previous tests, we found that, for x number of cores, From 8d78f13ef1c328cddeb06475766c9115a18770cb Mon Sep 17 00:00:00 2001 From: lfu-ps <83976250+lfu-ps@users.noreply.github.com> Date: Fri, 10 Sep 2021 17:08:54 -0700 Subject: [PATCH 29/54] Enhance openflow communication performance (#261) --- .clang-format | 2 +- CMakeLists.txt | 2 +- README.md | 1 + build/Dockerfile | 73 +- build/aca-machine-init.sh | 97 +- build/build.sh | 4 +- include/aca_net_config.h | 2 + include/aca_on_demand_engine.h | 4 +- include/aca_ovs_control.h | 3 +- include/aca_ovs_l2_programmer.h | 27 +- include/aca_zeta_oam_server.h | 2 +- include/libfluid-base/OFClient.hh | 56 + include/libfluid-base/OFConnection.hh | 235 ++ include/libfluid-base/OFServer.hh | 149 + include/libfluid-base/OFServerSettings.hh | 180 + include/libfluid-base/TLS.hh | 39 + include/libfluid-base/base/BaseOFClient.hh | 67 + .../libfluid-base/base/BaseOFConnection.hh | 229 ++ include/libfluid-base/base/BaseOFServer.hh | 106 + include/libfluid-base/base/EventLoop.hh | 87 + include/libfluid-base/base/config.h | 60 + include/libfluid-base/base/of.hh | 147 + include/libfluid-msg/of10/of10action.hh | 321 ++ include/libfluid-msg/of10/of10common.hh | 213 ++ include/libfluid-msg/of10/of10match.hh | 115 + include/libfluid-msg/of10/openflow-10.h | 889 +++++ include/libfluid-msg/of10msg.hh | 880 +++++ include/libfluid-msg/of13/of13action.hh | 419 +++ include/libfluid-msg/of13/of13common.hh | 784 +++++ include/libfluid-msg/of13/of13instruction.hh | 303 ++ include/libfluid-msg/of13/of13match.hh | 1233 +++++++ include/libfluid-msg/of13/of13meter.hh | 330 ++ include/libfluid-msg/of13/openflow-13.h | 1754 ++++++++++ include/libfluid-msg/of13msg.hh | 1596 +++++++++ include/libfluid-msg/ofcommon/action.hh | 138 + include/libfluid-msg/ofcommon/common.hh | 559 ++++ include/libfluid-msg/ofcommon/msg.hh | 508 +++ .../libfluid-msg/ofcommon/openflow-common.hh | 176 + include/libfluid-msg/util/ethaddr.hh | 52 + include/libfluid-msg/util/ipaddr.hh | 60 + include/libfluid-msg/util/util.h | 170 + include/of_controller.h | 109 + include/of_message.h | 95 + include/ovs_control.h | 249 +- src/CMakeLists.txt | 51 +- src/README.md | 8 +- src/aca_main.cpp | 50 +- src/dhcp/aca_dhcp_server.cpp | 29 +- src/grpc/CMakeLists.txt | 4 +- src/net_config/aca_net_config.cpp | 31 + src/on_demand/aca_on_demand_engine.cpp | 13 +- src/ovs/aca_arp_responder.cpp | 13 +- src/ovs/aca_ovs_l2_programmer.cpp | 220 +- src/ovs/aca_ovs_l3_programmer.cpp | 108 +- src/ovs/aca_vlan_manager.cpp | 48 +- src/ovs/libfluid-base/OFClient.cc | 66 + src/ovs/libfluid-base/OFConnection.cc | 86 + src/ovs/libfluid-base/OFServer.cc | 270 ++ src/ovs/libfluid-base/OFServerSettings.cc | 108 + src/ovs/libfluid-base/TLS.cc | 99 + src/ovs/libfluid-base/base/BaseOFClient.cc | 306 ++ .../libfluid-base/base/BaseOFConnection.cc | 358 ++ src/ovs/libfluid-base/base/BaseOFServer.cc | 270 ++ src/ovs/libfluid-base/base/EventLoop.cc | 78 + src/ovs/libfluid-msg/of10/of10action.cc | 501 +++ src/ovs/libfluid-msg/of10/of10common.cc | 333 ++ src/ovs/libfluid-msg/of10/of10match.cc | 157 + src/ovs/libfluid-msg/of10msg.cc | 1506 +++++++++ src/ovs/libfluid-msg/of13/of13action.cc | 626 ++++ src/ovs/libfluid-msg/of13/of13common.cc | 1337 ++++++++ src/ovs/libfluid-msg/of13/of13instruction.cc | 416 +++ src/ovs/libfluid-msg/of13/of13match.cc | 2733 +++++++++++++++ src/ovs/libfluid-msg/of13/of13meter.cc | 492 +++ src/ovs/libfluid-msg/of13msg.cc | 2940 +++++++++++++++++ src/ovs/libfluid-msg/ofcommon/action.cc | 226 ++ src/ovs/libfluid-msg/ofcommon/common.cc | 436 +++ src/ovs/libfluid-msg/ofcommon/msg.cc | 479 +++ src/ovs/libfluid-msg/util/ethaddr.cc | 65 + src/ovs/libfluid-msg/util/ipaddr.cc | 130 + src/ovs/of_controller.cpp | 274 ++ src/ovs/of_message.cpp | 298 ++ src/ovs/ovs_control.cpp | 2133 ++++++------ src/proto3/CMakeLists.txt | 2 +- src/zeta/aca_zeta_oam_server.cpp | 19 +- test/gtest/aca_test_oam.cpp | 7 +- test/gtest/aca_test_openflow.cpp | 11 +- test/gtest/aca_test_ovs_util.cpp | 7 +- 87 files changed, 28518 insertions(+), 1351 deletions(-) create mode 100644 include/libfluid-base/OFClient.hh create mode 100644 include/libfluid-base/OFConnection.hh create mode 100644 include/libfluid-base/OFServer.hh create mode 100644 include/libfluid-base/OFServerSettings.hh create mode 100644 include/libfluid-base/TLS.hh create mode 100644 include/libfluid-base/base/BaseOFClient.hh create mode 100644 include/libfluid-base/base/BaseOFConnection.hh create mode 100644 include/libfluid-base/base/BaseOFServer.hh create mode 100644 include/libfluid-base/base/EventLoop.hh create mode 100644 include/libfluid-base/base/config.h create mode 100644 include/libfluid-base/base/of.hh create mode 100644 include/libfluid-msg/of10/of10action.hh create mode 100644 include/libfluid-msg/of10/of10common.hh create mode 100644 include/libfluid-msg/of10/of10match.hh create mode 100644 include/libfluid-msg/of10/openflow-10.h create mode 100644 include/libfluid-msg/of10msg.hh create mode 100644 include/libfluid-msg/of13/of13action.hh create mode 100644 include/libfluid-msg/of13/of13common.hh create mode 100644 include/libfluid-msg/of13/of13instruction.hh create mode 100644 include/libfluid-msg/of13/of13match.hh create mode 100644 include/libfluid-msg/of13/of13meter.hh create mode 100644 include/libfluid-msg/of13/openflow-13.h create mode 100644 include/libfluid-msg/of13msg.hh create mode 100644 include/libfluid-msg/ofcommon/action.hh create mode 100644 include/libfluid-msg/ofcommon/common.hh create mode 100644 include/libfluid-msg/ofcommon/msg.hh create mode 100644 include/libfluid-msg/ofcommon/openflow-common.hh create mode 100644 include/libfluid-msg/util/ethaddr.hh create mode 100644 include/libfluid-msg/util/ipaddr.hh create mode 100644 include/libfluid-msg/util/util.h create mode 100644 include/of_controller.h create mode 100644 include/of_message.h create mode 100644 src/ovs/libfluid-base/OFClient.cc create mode 100644 src/ovs/libfluid-base/OFConnection.cc create mode 100644 src/ovs/libfluid-base/OFServer.cc create mode 100644 src/ovs/libfluid-base/OFServerSettings.cc create mode 100644 src/ovs/libfluid-base/TLS.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFClient.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFConnection.cc create mode 100644 src/ovs/libfluid-base/base/BaseOFServer.cc create mode 100644 src/ovs/libfluid-base/base/EventLoop.cc create mode 100644 src/ovs/libfluid-msg/of10/of10action.cc create mode 100644 src/ovs/libfluid-msg/of10/of10common.cc create mode 100644 src/ovs/libfluid-msg/of10/of10match.cc create mode 100644 src/ovs/libfluid-msg/of10msg.cc create mode 100644 src/ovs/libfluid-msg/of13/of13action.cc create mode 100644 src/ovs/libfluid-msg/of13/of13common.cc create mode 100644 src/ovs/libfluid-msg/of13/of13instruction.cc create mode 100644 src/ovs/libfluid-msg/of13/of13match.cc create mode 100644 src/ovs/libfluid-msg/of13/of13meter.cc create mode 100644 src/ovs/libfluid-msg/of13msg.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/action.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/common.cc create mode 100644 src/ovs/libfluid-msg/ofcommon/msg.cc create mode 100644 src/ovs/libfluid-msg/util/ethaddr.cc create mode 100644 src/ovs/libfluid-msg/util/ipaddr.cc create mode 100644 src/ovs/of_controller.cpp create mode 100644 src/ovs/of_message.cpp diff --git a/.clang-format b/.clang-format index 7de93f24..9c0091df 100644 --- a/.clang-format +++ b/.clang-format @@ -440,7 +440,7 @@ IncludeCategories: IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false #IndentPPDirectives: None # Unknown to clang-format-5.0 -IndentWidth: 2 +IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dc4e529..3f473d34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ set(CPPKAFKA_VERSION "${CPPKAFKA_VERSION_MAJOR}.${CPPKAFKA_VERSION_MINOR}.${CPPK set(RDKAFKA_MIN_VERSION 0x00090400) #add_compile_options(-O0) # enable no optimization during development -add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror) +add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Wno-error -Wno-unused-variable -Wno-unused-parameter -Wno-sequence-point -Wno-parentheses -Wno-pedantic -Wno-reorder -Wno-sign-compare) add_subdirectory(src) add_subdirectory(test) diff --git a/README.md b/README.md index 6a766db1..0ad14b22 100644 --- a/README.md +++ b/README.md @@ -51,5 +51,6 @@ This main repository of Alcor Control Agent is organized as follows: ## Notes * ovs_control.h and ovs_control.cpp is based on https://github.com/openvswitch/ovs/blob/master/utilities/ovs-ofctl.c +* libfluid-base/*.h(*.cpp) and libfluid-msg/*.h(*.cpp) are based on https://github.com/OpenNetworkingFoundation/libfluid, the usage of derived class is based on https://github.com/OpenNetworkingFoundation/libfluid/tree/master/examples/controller * aca_grpc.cpp is based on https://github.com/grpc/grpc/blob/v1.30.0/examples/cpp/route_guide/route_guide_server.cc * HashMap.h and HashNode.h is based on https://github.com/kshk123/hashMap diff --git a/build/Dockerfile b/build/Dockerfile index 69462dea..68b102ea 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -13,6 +13,8 @@ # 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. FROM fwnetworking/ubuntu:18.04 +RUN rm -rf /var/local/git && mkdir -p /var/local/git + RUN echo "1--- installing common dependencies ---" && \ apt-get update -y && apt-get install -y \ rpcbind \ @@ -108,22 +110,83 @@ RUN echo "4--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ -ENV OVS_RELEASE_TAG branch-2.12 +ENV OVS_INCLUDE_HEADERS='include/openvswitch/compiler.h \ + include/openvswitch/dynamic-string.h \ + include/openvswitch/hmap.h \ + include/openvswitch/flow.h \ + include/openvswitch/geneve.h \ + include/openvswitch/json.h \ + include/openvswitch/list.h \ + include/openvswitch/netdev.h \ + include/openvswitch/match.h \ + include/openvswitch/meta-flow.h \ + include/openvswitch/ofpbuf.h \ + include/openvswitch/ofp-actions.h \ + include/openvswitch/ofp-ed-props.h \ + include/openvswitch/ofp-errors.h \ + include/openvswitch/ofp-msgs.h \ + include/openvswitch/ofp-parse.h \ + include/openvswitch/ofp-print.h \ + include/openvswitch/ofp-prop.h \ + include/openvswitch/ofp-util.h \ + include/openvswitch/packets.h \ + include/openvswitch/poll-loop.h \ + include/openvswitch/rconn.h \ + include/openvswitch/shash.h \ + include/openvswitch/thread.h \ + include/openvswitch/token-bucket.h \ + include/openvswitch/tun-metadata.h \ + include/openvswitch/type-props.h \ + include/openvswitch/types.h \ + include/openvswitch/util.h \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ + include/openvswitch/vlog.h \ + include/openvswitch/nsh.h ' +ENV OPENFLOW_HEADERS='include/openflow/intel-ext.h \ + include/openflow/netronome-ext.h \ + include/openflow/nicira-ext.h \ + include/openflow/openflow-1.0.h \ + include/openflow/openflow-1.1.h \ + include/openflow/openflow-1.2.h \ + include/openflow/openflow-1.3.h \ + include/openflow/openflow-1.4.h \ + include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ + include/openflow/openflow-common.h \ + include/openflow/openflow.h ' RUN echo "5--- installing openvswitch dependancies ---" && \ - git clone -b ${OVS_RELEASE_TAG} https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + apt-get install -y python2.7 && \ + wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + python2.7 /tmp/get-pip.py && \ + pip2 install six && \ + apt-get install -y libevent-dev && \ + mkdir -p /var/local/git/openvswitch && \ + cd /var/local/git/openvswitch && \ + git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ ./boot.sh && \ ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ make && \ make install && \ - mkdir -p /usr/local/include/openvswitch && \ - cp /var/local/git/openvswitch/lib/vconn-provider.h /usr/local/include/openvswitch/vconn-provider.h && \ + cp ./lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp ./include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + cd /var/local/git/openvswitch && \ + wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ + tar -xvzf openvswitch-2.9.8.tar.gz && \ + cd openvswitch-2.9.8 && \ + ./configure && make && \ + cp ${OVS_INCLUDE_HEADERS} /usr/local/include/openvswitch && \ + cp ${OPENFLOW_HEADERS} /usr/local/include/openflow && \ + cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ rm -rf /var/local/git/openvswitch && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ ENV PULSAR_RELEASE_TAG='pulsar-2.6.1' -RUN echo "7--- installing pulsar dependacies ---" && \ +RUN echo "6--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client-dev.deb -O /var/local/git/pulsar/apache-pulsar-client-dev.deb && \ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index a8ab98d3..add7077c 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # MIT License # Copyright(c) 2020 Futurewei Cloud # @@ -12,20 +14,30 @@ # 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. -#!/bin/bash - BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" +rm -rf /var/local/git +mkdir -p /var/local/git + # TODO: remove the unneeded dependencies -echo "1--- installing mizar dependencies ---" && \ +echo "1--- installing common dependencies ---" && \ apt-get update -y && apt-get install -y \ rpcbind \ rsyslog \ build-essential \ + make \ + g++ \ + unzip \ + cmake \ clang-9 \ llvm-9 \ libelf-dev \ + doxygen \ + zlib1g-dev \ + libssl-dev \ + libboost-program-options-dev \ + libboost-all-dev \ iproute2 \ net-tools \ iputils-ping \ @@ -35,7 +47,15 @@ echo "1--- installing mizar dependencies ---" && \ python3-pip \ netcat \ libcmocka-dev \ - lcov + lcov \ + git \ + autoconf \ + automake \ + dh-autoreconf \ + pkg-config \ + libtool \ + wget \ + uuid-dev pip3 install httpserver netaddr echo "2--- installing librdkafka ---" && \ @@ -105,15 +125,76 @@ echo "5--- cloning grpc repo ---" && \ rm -rf /var/local/git/grpc && \ cd ~ -OVS_RELEASE_TAG="branch-2.12" +OVS_INCLUDE_HEADERS="include/openvswitch/compiler.h \ + include/openvswitch/dynamic-string.h \ + include/openvswitch/hmap.h \ + include/openvswitch/flow.h \ + include/openvswitch/geneve.h \ + include/openvswitch/json.h \ + include/openvswitch/list.h \ + include/openvswitch/netdev.h \ + include/openvswitch/match.h \ + include/openvswitch/meta-flow.h \ + include/openvswitch/ofpbuf.h \ + include/openvswitch/ofp-actions.h \ + include/openvswitch/ofp-ed-props.h \ + include/openvswitch/ofp-errors.h \ + include/openvswitch/ofp-msgs.h \ + include/openvswitch/ofp-parse.h \ + include/openvswitch/ofp-print.h \ + include/openvswitch/ofp-prop.h \ + include/openvswitch/ofp-util.h \ + include/openvswitch/packets.h \ + include/openvswitch/poll-loop.h \ + include/openvswitch/rconn.h \ + include/openvswitch/shash.h \ + include/openvswitch/thread.h \ + include/openvswitch/token-bucket.h \ + include/openvswitch/tun-metadata.h \ + include/openvswitch/type-props.h \ + include/openvswitch/types.h \ + include/openvswitch/util.h \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ + include/openvswitch/vlog.h \ + include/openvswitch/nsh.h " +OPENFLOW_HEADERS="include/openflow/intel-ext.h \ + include/openflow/netronome-ext.h \ + include/openflow/nicira-ext.h \ + include/openflow/openflow-1.0.h \ + include/openflow/openflow-1.1.h \ + include/openflow/openflow-1.2.h \ + include/openflow/openflow-1.3.h \ + include/openflow/openflow-1.4.h \ + include/openflow/openflow-1.5.h \ + include/openflow/openflow-1.6.h \ + include/openflow/openflow-common.h \ + include/openflow/openflow.h " echo "6--- installing openvswitch dependancies ---" && \ - git clone -b $OVS_RELEASE_TAG https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ + sudo rm -f /tmp/get-pip.py > /dev/null 2>&1 && \ + sudo apt-get install -y python2.7 && \ + sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /tmp/get-pip.py && \ + sudo python2.7 /tmp/get-pip.py && \ + sudo pip2 install six && \ + apt-get install -y libevent-dev && \ + mkdir -p /var/local/git/openvswitch && \ + git clone -b "branch-2.12" https://github.com/openvswitch/ovs.git /var/local/git/openvswitch && \ cd /var/local/git/openvswitch && \ ./boot.sh && \ ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc --enable-shared --enable-ndebug && \ make && \ make install && \ - cp /var/local/git/openvswitch/lib/vconn-provider.h /usr/local/include/openvswitch/vconn-provider.h && \ + cp ./lib/vconn-provider.h /usr/local/include/openvswitch && \ + cp ./include/openvswitch/namemap.h /usr/local/include/openvswitch && \ + cd /var/local/git/openvswitch && \ + wget https://www.openvswitch.org/releases/openvswitch-2.9.8.tar.gz && \ + tar -xvzf openvswitch-2.9.8.tar.gz && \ + cd openvswitch-2.9.8 && \ + ./configure && make && \ + cp $OVS_INCLUDE_HEADERS /usr/local/include/openvswitch && \ + cp $OPENFLOW_HEADERS /usr/local/include/openflow && \ + cp ./lib/.libs/libopenvswitch.a /usr/local/lib/ && \ rm -rf /var/local/git/openvswitch && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ @@ -131,7 +212,7 @@ echo "7--- installing pulsar dependacies ---" && \ echo "8--- building alcor-control-agent" cd $BUILD/.. && cmake . && make -if [ "$1" == "delete-bridges" ]; then +if [ -n "$1" -a "$1" = "delete-bridges" ]; then echo "9--- deleting br-tun and br-int if requested" PATH=$PATH:/usr/local/share/openvswitch/scripts \ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib diff --git a/build/build.sh b/build/build.sh index dd263c89..bdfad4a8 100755 --- a/build/build.sh +++ b/build/build.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # MIT License # Copyright(c) 2020 Futurewei Cloud # @@ -12,8 +14,6 @@ # 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. -#!/bin/bash - BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" echo "build path is $BUILD" diff --git a/include/aca_net_config.h b/include/aca_net_config.h index cbc3333f..c0db0e08 100644 --- a/include/aca_net_config.h +++ b/include/aca_net_config.h @@ -56,6 +56,8 @@ class Aca_Net_Config { int execute_system_command(string cmd_string, ulong &culminative_time); + std::string execute_system_command_with_return(string cmd_string); + // compiler will flag error when below is called Aca_Net_Config(Aca_Net_Config const &) = delete; void operator=(Aca_Net_Config const &) = delete; diff --git a/include/aca_on_demand_engine.h b/include/aca_on_demand_engine.h index b2f21eeb..2629826f 100644 --- a/include/aca_on_demand_engine.h +++ b/include/aca_on_demand_engine.h @@ -21,9 +21,11 @@ #include "common.pb.h" #include -#include +//#include +#include #include #include +#include #include "hashmap/HashMap.h" #include #include diff --git a/include/aca_ovs_control.h b/include/aca_ovs_control.h index e5a2137c..151fd66b 100644 --- a/include/aca_ovs_control.h +++ b/include/aca_ovs_control.h @@ -20,7 +20,8 @@ #define STDOUT_FILENO 1 /* Standard output. */ #include -#include +//#include +#include #include // OVS monitor implementation class diff --git a/include/aca_ovs_l2_programmer.h b/include/aca_ovs_l2_programmer.h index a1d000ff..f8dc7a48 100644 --- a/include/aca_ovs_l2_programmer.h +++ b/include/aca_ovs_l2_programmer.h @@ -16,7 +16,10 @@ #define ACA_OVS_L2_PROGRAMMER_H #include "goalstateprovisioner.grpc.pb.h" +#undef UNUSED +#include "of_controller.h" #include +#include #define PRIORITY_HIGH 50 #define PRIORITY_MID 25 @@ -29,14 +32,18 @@ class ACA_OVS_L2_Programmer { public: static ACA_OVS_L2_Programmer &get_instance(); - std::vector host_ips_vector; - void get_local_host_ips(); bool is_ip_on_the_same_host(const std::string hosting_port_ip); int setup_ovs_bridges_if_need(); + int setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port); + + void clean_up_ovs_controller(); + + std::string get_system_port_id(std::string port_name); + int create_port(const std::string vpc_id, const std::string port_name, const std::string virtual_ip, const std::string virtual_mac, uint tunnel_id, ulong &culminative_time); @@ -57,13 +64,29 @@ class ACA_OVS_L2_Programmer { void execute_openflow_command(const std::string cmd_string, ulong &culminative_time, int &overall_rc); + void execute_openflow(ulong &culminative_time, + const std::string bridge, + const std::string flow_string, + const std::string action = "add"); + + void packet_out(const char *bridge, const char *options); + // compiler will flag the error when below is called. ACA_OVS_L2_Programmer(ACA_OVS_L2_Programmer const &) = delete; void operator=(ACA_OVS_L2_Programmer const &) = delete; private: + OFController* ofctrl; + std::unordered_map port_id_map; + std::vector host_ips_vector; + ACA_OVS_L2_Programmer(){}; + ~ACA_OVS_L2_Programmer(){}; + + std::unordered_map get_ovs_bridge_mapping(); + + std::unordered_map get_system_port_ids(); }; } // namespace aca_ovs_l2_programmer #endif // #ifndef ACA_OVS_L2_PROGRAMMER_H \ No newline at end of file diff --git a/include/aca_zeta_oam_server.h b/include/aca_zeta_oam_server.h index c25e8367..14988640 100644 --- a/include/aca_zeta_oam_server.h +++ b/include/aca_zeta_oam_server.h @@ -19,7 +19,7 @@ #include #include #include -#include +//#include #include "hashmap/HashMap.h" #include "goalstateprovisioner.grpc.pb.h" diff --git a/include/libfluid-base/OFClient.hh b/include/libfluid-base/OFClient.hh new file mode 100644 index 00000000..6a71761c --- /dev/null +++ b/include/libfluid-base/OFClient.hh @@ -0,0 +1,56 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +#pragma once + +#include "base/BaseOFConnection.hh" +#include "base/BaseOFClient.hh" +#include "OFServer.hh" +#include "OFConnection.hh" +#include "OFServerSettings.hh" +#include + +namespace fluid_base { + +class OFClient : private BaseOFClient, private OFConnectionProcessor, public OFHandler { +public: + OFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure, + const struct OFServerSettings ofsc = OFServerSettings()); + virtual ~OFClient(); + + virtual bool start(bool block = false); + + virtual void stop(); + + void set_config(OFServerSettings ofsc); + + // virtual void connection_callback(OFConnection *conn, OFConnection::Event event_type){}; + // virtual void message_callback(OFConnection *conn, uint8_t type, void *data, size_t len){}; + virtual void free_data(void* data) final; + +protected: + void base_message_callback(BaseOFConnection* c, void* data, size_t len) final; + void base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) final; + + void on_new_conn(OFConnection* cc) final; + + std::unique_ptr conn; +}; + +} // namespace fluid_base \ No newline at end of file diff --git a/include/libfluid-base/OFConnection.hh b/include/libfluid-base/OFConnection.hh new file mode 100644 index 00000000..a761b465 --- /dev/null +++ b/include/libfluid-base/OFConnection.hh @@ -0,0 +1,235 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __OFCONNECTION_HH__ +#define __OFCONNECTION_HH__ + +#include +#include + +namespace fluid_base { +class BaseOFConnection; +class OFHandler; + +/** +An OFConnection represents an OpenFlow connection with basic protocol +knowledge. It wraps a BaseOFConnection object, providing further abstractions +on top of it. +*/ +class OFConnection { +public: + /** + Create an OFConnection. + + @param c the BaseOFConnection object that this OFConnection will represent + @param ofhandler the OFHandler instance responsible for this OFConnection + */ + OFConnection(BaseOFConnection* c, OFHandler* ofhandler); + + /** Represents the state of an OFConnection. */ + enum State { + /** Sent hello message, waiting for reply */ + STATE_HANDSHAKE, + /** Version negotiation done, features request received */ + STATE_RUNNING, + /** Version negotiation failed, connection closed */ + STATE_FAILED, + /** OFConnection is down, unable to send/receive data (it will be closed + automatically). It represents a disconnection event at the controller + level. */ + STATE_DOWN + }; + + /** + OFConnection events. In the descriptions below, "safe to use" means that + messages can be sent and received normally according to the OpenFlow + specification. + */ + enum Event { + /** The connection has been started, but it is still waiting for the + OpenFlow handshake. It is not safe to use the connection. */ + EVENT_STARTED, + + /** The connection has been established (OpenFlow handshake complete). + It is safe to use the connection. */ + EVENT_ESTABLISHED, + + /** The version negotiation has failed because the parts cannot talk in + a common OpenFlow version. It is not safe to use the connection. */ + EVENT_FAILED_NEGOTIATION, + + /** The connection has been closed. It is not safe to use the + connection. */ + EVENT_CLOSED, + + /** The connection has been closed due to inactivity (no response to + echo requests). It is not safe to use the connection. */ + EVENT_DEAD, + }; + + /** Get the connection ID. */ + int get_id(); + + /** Get switch IP address. */ + std::string get_peer_address(); + + /** Check if the connection is alive (responding to echo requests). */ + bool is_alive(); + + /** Update the liveness state of the connection. */ + void set_alive(bool alive); + + /** + Get the connection state. See #OFConnection::State. + */ + uint8_t get_state(); + + /** + Set the connection state. See #OFConnection::State. + + @param state the new state. + */ + void set_state(OFConnection::State state); + + /** + Get the negotiated OpenFlow version for the connection (OpenFlow protocol + version number). Note that this is not an OFVersion value. It is the value + that goes into the OpenFlow header (e.g.: 4 for OpenFlow 1.3). */ + uint8_t get_version(); + + /** + Set a negotiated version for the connection. (OpenFlow protocol version + number). Note that this is not an OFVersion value. It is the value + that goes into the OpenFlow header (e.g.: 4 for OpenFlow 1.3). + + @param version an OpenFlow version number + */ + void set_version(uint8_t version); + + /** + Return the OFHandler instance responsible for the connection. + */ + OFHandler* get_ofhandler(); + + /** + Send data to through the connection. + + @param data the binary data to send + @param len length of the binary data (in bytes) + */ + void send(void* data, size_t len); + + /** + Set up a function to be called forever with an argument at a regular + interval. This is a utility function provided for no specific use case, but + rather because it is frequently needed. + + This method is thread-safe. + + @param cb the callback function. It should accept a void* argument and + return a void*. + @param interval interval in milisseconds + @param arg an argument to the callback function + */ + void add_timed_callback(void* (*cb)(void*), int interval, void* arg); + // TODO: add the option for the function to unschedule itself by returning + // false + + /** + Get application data. This data is any piece of data you might want to + associated with this OFConnection object. + */ + void* get_application_data(); + + /** + Set application data. + + See OFConnection::get_application_data. + + @param data a pointer to application data + */ + void set_application_data(void* data); + + /** + Close the connection. + This will not trigger OFServer::connection_callback. + */ + void close(); + +private: + BaseOFConnection* conn; + int id; + std::string peer_address; + State state; + uint8_t version; + bool alive; + OFHandler* ofhandler; + void* application_data; +}; + +/** +OFHandler is an abstract class. Its methods must be implemented by classes that +deal with OFConnection events (usually classes that manage one or more +OFConnection objects). +*/ +class OFHandler { +public: + virtual ~OFHandler() {} + + /** + Callback for connection events. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it will possibly be called + from several threads (on which connection events are being created). + + @param conn the OFConnection on which the message was received + @param event_type the event type (see #Event) + */ + virtual void connection_callback(OFConnection* conn, OFConnection::Event event_type) = 0; + + /** + Callback for new messages. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it will possibly be called + from several threads (on which message events are being created). + + By default, the message data will managed (freed) for you. If you want a + zero-copy behavior, see OFServerSettings::keep_data_ownership. + + @param conn the OFConnection on which the message was received + @param type OpenFlow message type + @param data binary message data + @param len message length + */ + virtual void message_callback(OFConnection* conn, uint8_t type, void* data, size_t len) = 0; + + /** + Free the data passed to OFHandler::message_callback. + */ + virtual void free_data(void* data) = 0; +}; + +} + +#endif diff --git a/include/libfluid-base/OFServer.hh b/include/libfluid-base/OFServer.hh new file mode 100644 index 00000000..531b26ef --- /dev/null +++ b/include/libfluid-base/OFServer.hh @@ -0,0 +1,149 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __OFSERVER_HH__ +#define __OFSERVER_HH__ + +#include + +#include + +#include "base/BaseOFConnection.hh" +#include "base/BaseOFServer.hh" +#include "OFConnection.hh" +#include "OFServerSettings.hh" + +/** +Classes for creating an OpenFlow server that listens to connections and handles +events. +*/ +namespace fluid_base { +class OFConnectionProcessor { +public: + OFConnectionProcessor(OFHandler* h); + + void set_config(OFServerSettings ofsc); + void base_connection_callback(BaseOFConnection* conn, BaseOFConnection::Event event_type); + void base_message_callback(BaseOFConnection* conn, void* data, size_t len); + +private: + static void* send_echo(void* arg); + void free_data(void* data); + + virtual void on_new_conn(OFConnection* cc) = 0; + +private: + OFServerSettings ofsc; + OFHandler* _handler; +}; +/** +An OFServer manages OpenFlow connections and abstracts their events through +callbacks. It provides some of the basic functionalities: OpenFlow connection +setup and liveness check. + +Tipically a controller or low-level controller base class will inherit from +OFServer and implement the message_callback and connection_callback methods +to implement further functionality. +*/ +class OFServer : private BaseOFServer, private OFConnectionProcessor, public OFHandler { +public: + /** + Create an OFServer. + + @param address address to bind the server + @param port TCP port on which the server will listen + @param nthreads number of threads to run. Connections will be attributed to + event loops running on threads on a round-robin fashion. + The first event loop will also listen for new connections. + @param secure whether the connections should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init + before you can use this feature. + @param ofsc the optional server configuration parameters. If no value is + provided, default settings will be used. See OFServerSettings. + */ + OFServer(const char* address, + const int port, + const int nthreads = 4, + const bool secure = false, + const struct OFServerSettings ofsc = OFServerSettings()); + virtual ~OFServer(); + + /** + Start the server. It will listen at the port declared in the + constructor, handling connections in different threads and optionally + blocking the calling thread until OFServer::stop is called. + + @param block block the calling thread while the server is running + */ + // We reimplement this so that SWIG bindings don't have know BaseOFServer + virtual bool start(bool block = false); + + /** + Stop the server. It will close all connections, ask the theads handling + connections to finish. + + It will eventually unblock OFServer::start if it is blocking. + */ + virtual void stop(); + + /** + Retrieve an OFConnection object associated with this OFServer with a given + id. + + @param id OFConnection id + */ + OFConnection* get_ofconnection(int id); + + /** + Set configuration parameters for this OFServer. + + This method should be called before OFServer::start is called. Doing + otherwise will result in undefined settings behavior. In theory, it will + work fine, but unpredictable behavior can happen, and some settings will + only apply to new connections. + + You will usually initialize the settings in the constructor. This method + is provided to give more flexibility to implementations. + + @param ofsc an OFServerSettings object with the desired settings + */ + void set_config(OFServerSettings ofsc); + + virtual void connection_callback(OFConnection* conn, OFConnection::Event event_type) {}; + virtual void message_callback(OFConnection* conn, uint8_t type, void* data, size_t len) {}; + virtual void free_data(void* data) override; + +protected: + OFServerSettings ofsc; + std::map ofconnections; + pthread_mutex_t ofconnections_lock; + + inline void lock_ofconnections() { + pthread_mutex_lock(&ofconnections_lock); + } + + inline void unlock_ofconnections() { + pthread_mutex_unlock(&ofconnections_lock); + } + + void base_message_callback(BaseOFConnection* c, void* data, size_t len) final; + void base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) final; + + void on_new_conn(OFConnection* cc) final; +}; +} + +#endif diff --git a/include/libfluid-base/OFServerSettings.hh b/include/libfluid-base/OFServerSettings.hh new file mode 100644 index 00000000..6a80c20f --- /dev/null +++ b/include/libfluid-base/OFServerSettings.hh @@ -0,0 +1,180 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __OFSERVERSETTINGS_HH__ +#define __OFSERVERSETTINGS_HH__ + +#include + +namespace fluid_base { + +#define ECHO_XID 0x0F +#define HELLO_XID 0x0F + +class OFServer; + +/** +Configuration parameters for an OFServer. These parameters specify the +OpenFlow behavior of a class that deals with OFConnection objects. +*/ +class OFServerSettings { +public: + /** + Create an OFServerSettings with default configuration values. + + Settings will have the following values by default: + - Only OpenFlow 1.0 is supported (a sane value for the most compatibility) + - `echo_interval`: `15` + - `liveness_check`: `true` + - `handshake`: `true` + - `dispatch_all_messages`: `false` + - `use_hello_elems`: `false` (to avoid compatibility issues with + existing software and hardware) + - `keep_data_ownership`: `true` (to simplify things) + */ + OFServerSettings(); + + /** + Add a supported version to the set of supported versions. + + Using this method will override the default version (1, OpenFlow 1.0). If + you call this method with version 4, only version 4 will be supported. If + you want to add support for version 1, you will need to do so explicitly, + so that you can choose only the versions you want, while still having a + nice default. + + @param version OpenFlow protocol version number (e.g.: 4 for OpenFlow 1.3) + */ + OFServerSettings& supported_version(const uint8_t version); + + /** + Return an array of OpenFlow versions bitmaps with the supported versions. + */ + uint32_t* supported_versions(); + + /** + Return the largest version number supported. + */ + uint8_t max_supported_version(); + + /** + Set the OpenFlow echo interval (in seconds). A connection will be closed if + no echo replies arrive in this interval, and echo requests will be + periodically sent using the same interval. + + @param echo_interval the echo interval (in seconds) + */ + OFServerSettings& echo_interval(const int echo_interval); + + /** + Return the echo interval. + */ + int echo_interval(); + + /** + Set whether the OFServer instance should perform liveness checks (timed + echo requests and replies). + + @param liveness_check true for liveness checking + */ + OFServerSettings& liveness_check(const bool liveness_check); + + /** + Return whether liveness check should be performed. + */ + bool liveness_check(); + + /** + Set whether the OFServer instance should perform OpenFlow handshakes (hello + messages, version negotiation and features request). + + @param handshake true for automatic OpenFlow handshakes + */ + OFServerSettings& handshake(const bool handshake); + + /** + Return whether handshake should be performed. + */ + bool handshake(); + + /** + Set whether the OFServer instance should forward all OpenFlow messages to + the user callback (OFHandler::message_callback), including those treated + for handshake and liveness check. + + @param dispatch_all_messages true to enable forwarding for all messages + */ + OFServerSettings& dispatch_all_messages(const bool dispatch_all_messages); + + /** + Return whether all messages should be dispatched. + */ + bool dispatch_all_messages(); + + /** + Set whether the OFServer instance should send and treat OpenFlow 1.3.1 + hello elements. + + See OFServerSettings::OFServerSettings for more details. + + @param use_hello_elements true to enable hello elems + */ + OFServerSettings& use_hello_elements(const bool use_hello_elements); + + /** + Return whether hello elements should be used. + */ + bool use_hello_elements(); + + /** + Set whether the OFServer instance should own and manage the message data + passed to its message callback (true) or if your application should be + responsible for it (false). + + See OFServerSettings::OFServerSettings for more details. + + @param keep_data_ownership true if OFServer is responsible for managing + message data, false if your application is. + + */ + OFServerSettings& keep_data_ownership(const bool keep_data_ownership); + + /** + Return whether message data pointer ownership belongs to OFServer (true) or + your application (false). + */ + bool keep_data_ownership(); + + private: + friend class OFServer; + + uint32_t _supported_versions; + uint8_t _max_supported_version; + + bool version_set_by_hand; + void add_version(const uint8_t version); + + int _echo_interval; + bool _liveness_check; + bool _handshake; + bool _dispatch_all_messages; + bool _use_hello_elements; + bool _keep_data_ownership; +}; + +} + +#endif diff --git a/include/libfluid-base/TLS.hh b/include/libfluid-base/TLS.hh new file mode 100644 index 00000000..168ee0d2 --- /dev/null +++ b/include/libfluid-base/TLS.hh @@ -0,0 +1,39 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file Functions for secure communication using SSL */ +#ifndef __SSL_IMPL_HH__ +#define __SSL_IMPL_HH__ + +namespace fluid_base { + /** SSL implementation pointer for internal library use. */ + extern void* tls_obj; + + /** Initialize SSL parameters. You must call this function before + asking any object to communicate in a secure manner. + + @param cert The controller's certificate signed by a CA + @param privkey The controller's private key to be used with the + certificate + @param trustedcert A CA certificate that signs certificates of trusted + switches */ + void libfluid_tls_init(const char* cert, const char* privkey, const char* trustedcert); + + /** Free SSL data. You must call this function after you don't need secure + communication anymore. */ + void libfluid_tls_clear(); +} + +#endif \ No newline at end of file diff --git a/include/libfluid-base/base/BaseOFClient.hh b/include/libfluid-base/base/BaseOFClient.hh new file mode 100644 index 00000000..6d3f312e --- /dev/null +++ b/include/libfluid-base/base/BaseOFClient.hh @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +#pragma once + +#include +#include + +#include "EventLoop.hh" +#include "BaseOFConnection.hh" + +#include + +namespace fluid_base { + +class BaseOFClient : public BaseOFHandler { +public: + BaseOFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure); + virtual ~BaseOFClient(); + + bool start(bool block = false); + void stop(); + + // BaseOFHandler methods + // virtual void base_connection_callback( + // BaseOFConnection* conn, + // BaseOFConnection::Event event_type) override; + // virtual void base_message_callback(BaseOFConnection* conn, void* data, size_t len); + virtual void free_data(void* data) override; + +protected: + bool connect(); + +private: + const std::string address; + const bool domainsocket; + const int port; + const bool secure; + + bool blocking; + + EventLoop* evloop; + pthread_t evthread; + int nconn; + + class LibEventBaseOFClient; + friend class LibEventBaseOFClient; + LibEventBaseOFClient* m_implementation; +}; + +} // namespace fluid_base \ No newline at end of file diff --git a/include/libfluid-base/base/BaseOFConnection.hh b/include/libfluid-base/base/BaseOFConnection.hh new file mode 100644 index 00000000..d9e1e65a --- /dev/null +++ b/include/libfluid-base/base/BaseOFConnection.hh @@ -0,0 +1,229 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __BASEOFCONNECTION_HH__ +#define __BASEOFCONNECTION_HH__ + +#include +#include +#include + +#include "EventLoop.hh" + +namespace fluid_base { +class BaseOFHandler; + +/** +A BaseOFConnection wraps the basic functionalities of a network connection with +OpenFlow-oriented messaging features. It uses an OFReadBuffer for building the +messages being read and dispatches events to a BaseOFHandler (who created it). + +This connection will tipically be wrapped by a higher-level connection object +(a manager object) providing further protocol semantics on top of it. +*/ +class BaseOFConnection { +public: + /** + Create a BaseOFConnection. + + @param id connection id + @param ofhandler the BaseOFHandler for this connection + @param evloop the EventLoop that will run this connection + @param fd the OS-level file descriptor for this connection + + @param secure whether the connection should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init before you + can use this feature. + */ + BaseOFConnection(int id, + BaseOFHandler* ofhandler, + EventLoop* evloop, + int fd, + bool secure, + std::string peer_address); + virtual ~BaseOFConnection(); + + /** BaseOFConnection events. */ + enum Event { + /** The connection has been successfully established */ + EVENT_UP, + /** The other end has ended the connection */ + EVENT_DOWN, + /** The connection resources have been released and freed */ + EVENT_CLOSED + }; + + /** + Send a message through this connection. + + This method is thread-safe. + + @param data binary message data + @param len message length in bytes + */ + void send(void* data, size_t len); + + /** + Set up a function to be called forever with an argument at a regular + interval. + + This method is thread-safe. + + @param cb the callback function. It should accept a void* argument and + return a void*. + @param interval interval in milisseconds + @param arg an argument to the callback function + */ + void add_timed_callback(void* (*cb)(void*), int interval, void* arg); + // TODO: add the option for the function to unschedule itself by returning + // false + + // TODO: these methods are not thread-safe, and they really aren't + // currently called from more than one thread. But perhaps we should + // consider that... + + /** + Set the manager for this connection. A manager provides further protocol + semantics on top of a BaseOFConnection. This manager will tipically be used + by an upper-level abstraction on top of BaseOFHandler to create its own + representation of an OpenFlow connection that uses this connection. + + This method is not thread-safe. + + @param manager the manager object + */ + void set_manager(void* manager); + + /** + Get the manager for this connection. See BaseOFConnection::set_manager. + + This method is not thread-safe. + */ + void* get_manager(); + + /** + Get the connection id. + */ + int get_id(); + + /** + Get switch IP address. + */ + std::string get_peer_address(); + + /** + Close this connection. It won't be closed immediately (remaining connection + and message callbacks may still be called). + + After it is closed, the resources associated with this connection will be + freed, and no more callbacks will be invoked. Performing any further + operations on this connection will lead to undefined behavior. + + This method is thread-safe. + */ + void close(); + + /** + Free the dynamically allocated data sent to the message callback. + + @param data dynamically allocated data sent to the message callback + */ + static void free_data(void* data); + +private: + int id; + EventLoop* evloop; + class OFReadBuffer; + OFReadBuffer* buffer; + void* manager; + bool secure; + BaseOFHandler* ofhandler; + std::string peer_address; + + bool running; + + // Types for internal use (timed callbacks) + struct timed_callback { + void* (*cb)(void*); + void* cb_arg; + void* data; + }; + std::vector timed_callbacks; + + void notify_msg_cb(void* data, size_t n); + void notify_conn_cb(BaseOFConnection::Event event_type); + void do_close(); + + class LibEventBaseOFConnection; + friend class LibEventBaseOFConnection; + LibEventBaseOFConnection* m_implementation; +}; + +/** +BaseOFHandler is an abstract class. Its methods must be implemented by classes +that deal with BaseOFConnection events (usually classes that manage one or more +BaseOFConnection objects). */ +class BaseOFHandler { +public: + virtual ~BaseOFHandler() {} + + /** + Callback for connection events. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it may be called by several + EventLoop instances, each running in a thread. + + @param conn the BaseOFConnection on which the message was received + @param event_type the event type (see #BaseOFConnectionEvent) + */ + virtual void base_connection_callback(BaseOFConnection* conn, + BaseOFConnection::Event event_type) + = 0; + + /** + Callback for new messages. + + This method blocks the event loop on which the connection is running, + preventing other connection's events from being handled. If you want to + perform a very long operation, try to queue it and return. + + The implementation must be thread-safe, because it may be called by several + EventLoop instances, each running in a thread. + + The message data will not be freed. To free it, you should call + BaseOFConnection::free_data when you are done with it. + + @param conn the BaseOFConnection on which the message was received + @param data binary message data + @param len message length + */ + virtual void base_message_callback(BaseOFConnection* conn, + void* data, + size_t len) = 0; + + /** + Free the data passed to BaseOFHandler::base_message_callback. + */ + virtual void free_data(void* data) = 0; +}; + +} + +#endif diff --git a/include/libfluid-base/base/BaseOFServer.hh b/include/libfluid-base/base/BaseOFServer.hh new file mode 100644 index 00000000..5377b154 --- /dev/null +++ b/include/libfluid-base/base/BaseOFServer.hh @@ -0,0 +1,106 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __BASEOFSERVER_HH__ +#define __BASEOFSERVER_HH__ + +#include +#include + +#include "EventLoop.hh" +#include "BaseOFConnection.hh" + +#include + +namespace fluid_base { + +/** +A BaseOFServer manages the very basic functions of OpenFlow connections, such +as notifying of new messages and network-level events. It is an abstract class +that should be overriden by another class to provide OpenFlow features. +*/ +class BaseOFServer : public BaseOFHandler { +public: + /** + Create a BaseOFServer. + + @param address address to bind the server + @param port TCP port on which the server will listen + @param nevloops number of event loops to run. Connections will be + attributed to event loops running on threads on a + round-robin fashion. The first event loop will listen for + new connections. + @param secure whether the connections should use TLS. TLS support must + compiled into the library and you need to call libfluid_ssl_init before you + can use this feature. + */ + BaseOFServer(const char* address, + const int port, + const int nevloops = 1, + const bool secure = false); + virtual ~BaseOFServer(); + + /** + Start the server. It will listen at the port declared in the + constructor, assigning connections to event loops running in threads and + optionally blocking the calling thread until BaseOFServer::stop is called. + + @param block block the calling thread while the server is running + */ + virtual bool start(bool block = false); + + /** + Stop the server. It will stop listening to new connections and signal the + event loops to stop running. + + It will eventually unblock BaseOFServer::start if it is blocking. + */ + virtual void stop(); + + // BaseOFHandler methods + virtual void base_connection_callback(BaseOFConnection* conn, + BaseOFConnection::Event event_type); + virtual void base_message_callback(BaseOFConnection* conn, + void* data, + size_t len) { printf("Calling fake msgcb\n"); }; + virtual void free_data(void* data); + +private: + // TODO: hide part of this in LibEventBaseOFServer + char* address; + char port[6]; + + EventLoop** eventloops; + EventLoop* main; + pthread_t* threads; + bool blocking; + bool secure; + + int eventloop; + int nthreads; + int nconn; + + bool listen(EventLoop* w); + EventLoop* choose_eventloop(); + + class LibEventBaseOFServer; + friend class LibEventBaseOFServer; + LibEventBaseOFServer* m_implementation; +}; + +} + +#endif diff --git a/include/libfluid-base/base/EventLoop.hh b/include/libfluid-base/base/EventLoop.hh new file mode 100644 index 00000000..8b8e9eb4 --- /dev/null +++ b/include/libfluid-base/base/EventLoop.hh @@ -0,0 +1,87 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +/** @file */ +#ifndef __EVENTLOOP_HH__ +#define __EVENTLOOP_HH__ + +namespace fluid_base { + +class BaseOFServer; +class BaseOFConnection; +class OvsdbClient; +class OvsdbConnection; +class BaseOFClient; + +/** +A EventLoop runs an event loop for connections. It will activate the callbacks +associated with them. The class using an EventLoop should tipically assign +incoming connections in a round-robin fashion. + +There might be more than one event loop in use in applications. In this case, +each EventLoop can be run in a thread. +*/ +// An EventLoop is pretty much a simple wrapper around libevent's event_base +class EventLoop { +public: + /** + Create a EventLoop. + + @param id event loop id + */ + EventLoop(int id); + ~EventLoop(); + + /** + Run this event loop (which will block the calling thread). When + EventLoop::stop is called, this method will unblock, run the callbacks + of pending events and return. + + Calling EventLoop::stop first will prevent this method from running. */ + void run(); + + /** + Force the event loop to stop. It will finish running the current event + callback and then force EventLoop::run to continue its flow (deal with + remaining events and quit). + + Calling this method first will prevent EventLoop::run from running. */ + void stop(); + + /** + This method is just an adapter for passing the EventLoop::run method to + pthread_create. */ + static void* thread_adapter(void* arg); + + +private: + int id; + bool stopped; + + friend class BaseOFServer; + friend class BaseOFConnection; + friend class OvsdbClient; + friend class OvsdbConnection; + friend class BaseOFClient; + void* get_base(); + + class LibEventEventLoop; + friend class LibEventEventLoop; + LibEventEventLoop* m_implementation; +}; + +} + +#endif \ No newline at end of file diff --git a/include/libfluid-base/base/config.h b/include/libfluid-base/base/config.h new file mode 100644 index 00000000..9cbddd07 --- /dev/null +++ b/include/libfluid-base/base/config.h @@ -0,0 +1,60 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if the system has OpenSSL TLS support */ +// for arm, this not work +// #define HAVE_TLS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "allanv@cpqd.com.br" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libfluid_base" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libfluid_base 1.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libfluid_base" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.cpqd.com.br/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 diff --git a/include/libfluid-base/base/of.hh b/include/libfluid-base/base/of.hh new file mode 100644 index 00000000..e3ea1216 --- /dev/null +++ b/include/libfluid-base/base/of.hh @@ -0,0 +1,147 @@ +/* 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. + */ + +/* OpenFlow: protocol between controller and datapath. + +This is a simplified version of the OpenFlow header that should be valid for +all OpenFlow versions. +*/ + +#ifndef OPENFLOW_OPENFLOW_H +#define OPENFLOW_OPENFLOW_H 1 + +#ifdef __KERNEL__ +#include +#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; })] +#else /* __cplusplus */ +#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] +#endif /* __cplusplus */ + +#ifndef SWIG +#define OFP_PACKED __attribute__((packed)) +#else +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ +}; + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_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_fluid_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 this element. */ +}; +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. */ + /* 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_fluid_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); + +/* 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, /* Hello protocol failed. */ +}; + +/* ofp_fluid_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, /* No compatible version. */ +}; + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_fluid_error_msg { + struct ofp_fluid_header header; + + uint16_t type; + uint16_t code; + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_error_msg) == 12); + +#endif diff --git a/include/libfluid-msg/of10/of10action.hh b/include/libfluid-msg/of10/of10action.hh new file mode 100644 index 00000000..d036972d --- /dev/null +++ b/include/libfluid-msg/of10/of10action.hh @@ -0,0 +1,321 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF10ACTION_H +#define OF10ACTION_H + +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "../ofcommon/action.hh" + +namespace fluid_msg { + +namespace of10 { + +class OutputAction: public Action { +private: + uint16_t port_; + uint16_t max_len_; +public: + OutputAction(); + OutputAction(uint16_t port, uint16_t max_len); + ~OutputAction() { + } + OutputAction* clone() { + return new OutputAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } + uint16_t max_len() { + return this->max_len_; + } + void max_len(uint16_t max_len) { + this->max_len_ = max_len; + } +}; + +class SetVLANVIDAction: public Action { +private: + uint16_t vlan_vid_; +public: + SetVLANVIDAction(); + SetVLANVIDAction(uint16_t vlan_vid); + ~SetVLANVIDAction() { + } + virtual SetVLANVIDAction* clone() { + return new SetVLANVIDAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t vlan_vid() { + return this->vlan_vid_; + } + void vlan_vid(uint16_t vlan_vid) { + this->vlan_vid_ = vlan_vid; + } +}; + +class SetVLANPCPAction: public Action { +private: + uint8_t vlan_pcp_; +public: + SetVLANPCPAction(); + SetVLANPCPAction(uint8_t vlan_pcp); + ~SetVLANPCPAction() { + } + virtual SetVLANPCPAction* clone() { + return new SetVLANPCPAction(*this); + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t vlan_pcp() { + return this->vlan_pcp_; + } + void vlan_pcp(uint8_t vlan_pcp) { + this->vlan_pcp_ = vlan_pcp; + } +}; + +class StripVLANAction: public Action { +public: + StripVLANAction(); + ~StripVLANAction() { + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual StripVLANAction* clone() { + return new StripVLANAction(*this); + } +}; + +class SetDLSrcAction: public Action { +private: + EthAddress dl_addr_; +public: + SetDLSrcAction(); + SetDLSrcAction(EthAddress dl_addr); + ~SetDLSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetDLSrcAction* clone() { + return new SetDLSrcAction(*this); + } + EthAddress dl_addr() { + return this->dl_addr_; + } + void dl_addr(const EthAddress &dl_addr) { + this->dl_addr_ = dl_addr; + } +}; + +class SetDLDstAction: public Action { +private: + EthAddress dl_addr_; +public: + SetDLDstAction(); + SetDLDstAction(EthAddress dl_addr); + ~SetDLDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetDLDstAction* clone() { + return new SetDLDstAction(*this); + } + EthAddress dl_addr() { + return this->dl_addr_; + } + void dl_addr(const EthAddress &dl_addr) { + this->dl_addr_ = dl_addr; + } + +}; + +class SetNWSrcAction: public Action { +private: + IPAddress nw_addr_; +public: + SetNWSrcAction(); + SetNWSrcAction(IPAddress nw_addr); + ~SetNWSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWSrcAction* clone() { + return new SetNWSrcAction(*this); + } + IPAddress nw_addr() { + return this->nw_addr_; + } + void nw_addr(const IPAddress &nw_addr) { + this->nw_addr_ = nw_addr; + } +}; + +class SetNWDstAction: public Action { +private: + IPAddress nw_addr_; +public: + SetNWDstAction(); + SetNWDstAction(IPAddress nw_addr); + ~SetNWDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWDstAction* clone() { + return new SetNWDstAction(*this); + } + IPAddress nw_addr() { + return this->nw_addr_; + } + void nw_addr(const IPAddress &nw_addr) { + this->nw_addr_ = nw_addr; + } +}; + +class SetNWTOSAction: public Action { +private: + uint8_t nw_tos_; +public: + SetNWTOSAction(); + SetNWTOSAction(uint8_t nw_tos); + ~SetNWTOSAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWTOSAction* clone() { + return new SetNWTOSAction(*this); + } + uint8_t nw_tos() { + return this->nw_tos_; + } + void nw_tos(uint8_t nw_tos) { + this->nw_tos_ = nw_tos; + } +}; + +class SetTPSrcAction: public Action { +private: + uint16_t tp_port_; +public: + SetTPSrcAction(); + SetTPSrcAction(uint16_t tp_port); + ~SetTPSrcAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetTPSrcAction* clone() { + return new SetTPSrcAction(*this); + } + IPAddress tp_port() { + return this->tp_port_; + } + void tp_port(uint16_t tp_port) { + this->tp_port_ = tp_port; + } +}; + +class SetTPDstAction: public Action { +private: + uint16_t tp_port_; +public: + SetTPDstAction(); + SetTPDstAction(uint16_t tp_port); + ~SetTPDstAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetTPDstAction* clone() { + return new SetTPDstAction(*this); + } + IPAddress tp_port() { + return this->tp_port_; + } + void tp_port(uint16_t tp_port) { + this->tp_port_ = tp_port; + } +}; + +class EnqueueAction: public Action { +private: + uint16_t port_; + uint32_t queue_id_; +public: + EnqueueAction(); + EnqueueAction(uint16_t port, uint32_t queue_id); + ~EnqueueAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual EnqueueAction* clone() { + return new EnqueueAction(*this); + } + uint16_t port() { + return this->port_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port(uint16_t port) { + this->port_ = port; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +class VendorAction: public Action { +private: + uint32_t vendor_; +public: + VendorAction(); + VendorAction(uint32_t vendor); + ~VendorAction() { + } + virtual bool equals(const Action & other); + virtual VendorAction* clone() { + return new VendorAction(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +} //End of namespace of10 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of10/of10common.hh b/include/libfluid-msg/of10/of10common.hh new file mode 100644 index 00000000..6191a018 --- /dev/null +++ b/include/libfluid-msg/of10/of10common.hh @@ -0,0 +1,213 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF10OPENFLOW_COMMON_H +#define OF10OPENFLOW_COMMON_H 1 + +#include +#include +#include "../util/util.h" +#include "../ofcommon/common.hh" +#include "openflow-10.h" +#include "of10action.hh" +#include "of10match.hh" + + +namespace fluid_msg { + +namespace of10 { + +class Port: public PortCommon { +private: + uint16_t port_no_; +public: + Port() { + } + Port(uint16_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer); + ~Port() { + } + bool operator==(const Port &other) const; + bool operator!=(const Port &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } + uint16_t port_no() { + return this->port_no_; + } + std::string name() { + return this->name_; + } +}; + +class QueuePropMinRate: public QueuePropRate { +public: + QueuePropMinRate() + : QueuePropRate(of10::OFPQT_MIN_RATE) { + } + QueuePropMinRate(uint16_t rate); + ~QueuePropMinRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMinRate* clone() { + return new QueuePropMinRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +/* Queue description*/ +class PacketQueue: public PacketQueueCommon { +public: + PacketQueue() { + } + PacketQueue(uint32_t queue_id); + PacketQueue(uint32_t queue_id, QueuePropertyList properties); + ~PacketQueue() { + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class FlowStats: public FlowStatsCommon { +private: + of10::Match match_; + ActionList actions_; +public: + FlowStats() { + } + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t cookie, uint64_t packet_count, uint64_t byte_count); + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t cookie, uint64_t packet_count, uint64_t byte_count, + of10::Match match, ActionList actions); + ~FlowStats() { + } + + bool operator==(const FlowStats &other) const; + bool operator!=(const FlowStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + of10::Match match() { + return this->match_; + } + ActionList actions() { + return this->actions_; + } + + void match(of10::Match match) { + this->match_ = match; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class TableStats: public TableStatsCommon { +private: + std::string name_; + uint32_t wildcards_; + uint32_t max_entries_; +public: + TableStats() { + } + + TableStats(uint8_t table_id, std::string name, uint32_t wildcards, + uint32_t max_entries, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count); + ~TableStats() { + } + + bool operator==(const TableStats &other) const; + bool operator!=(const TableStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::string name() { + return this->name_; + } + uint32_t wildcards() { + return this->wildcards_; + } + uint32_t max_entries() { + return this->max_entries_; + } + void name(std::string name) { + this->name_ = name; + } + void wildcards(uint32_t wildcards) { + this->wildcards_ = wildcards; + } + void max_entries(uint32_t max_entries) { + this->max_entries_ = max_entries; + } +}; + +class PortStats: public PortStatsCommon { +private: + uint16_t port_no_; +public: + PortStats() { + } + + PortStats(uint16_t port_no, struct port_rx_tx_stats tx_stats, + struct port_err_stats err_stats, uint64_t collisions); + ~PortStats() { + } + + bool operator==(const PortStats &other) const; + bool operator!=(const PortStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +class QueueStats: public QueueStatsCommon { +private: + uint16_t port_no_; +public: + QueueStats() { + } + + QueueStats(uint16_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors); + ~QueueStats() { + } + + bool operator==(const QueueStats &other) const; + bool operator!=(const QueueStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +} //End of namespace of10 +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/of10/of10match.hh b/include/libfluid-msg/of10/of10match.hh new file mode 100644 index 00000000..54b518e6 --- /dev/null +++ b/include/libfluid-msg/of10/of10match.hh @@ -0,0 +1,115 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF10OPENFLOW_MATCH_H +#define OF10OPENFLOW_MATCH_H 1 + +#include +#include +#include "../util/util.h" +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "openflow-10.h" + +namespace fluid_msg { + +namespace of10 { + +class Match { +private: + uint32_t wildcards_; /* Wildcard fields. */ + uint16_t in_port_; /* Input switch port. */ + EthAddress dl_src_; /* Ethernet source address. */ + EthAddress dl_dst_; /* Ethernet destination address. */ + uint16_t dl_vlan_; /* Input VLAN id. */ + uint8_t dl_vlan_pcp_; /* Input VLAN priority. */ + uint16_t dl_type_; /* Ethernet frame type. */ + uint8_t nw_tos_; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto_; /* IP protocol or lower 8 bits of + * ARP opcode. */ + IPAddress nw_src_; /* IP source address. */ + IPAddress nw_dst_; /* IP destination address. */ + uint16_t tp_src_; /* TCP/UDP source port. */ + uint16_t tp_dst_; /* TCP/UDP destination port. */ +public: + Match(); + ~Match() { + } + ; + bool operator==(const Match &other) const; + bool operator!=(const Match &other) const; + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t wildcards() { + return this->wildcards_; + } + uint16_t in_port() { + return this->in_port_; + } + EthAddress dl_src() { + return this->dl_src_; + } + EthAddress dl_dst() { + return this->dl_dst_; + } + uint16_t dl_vlan() { + return this->dl_vlan_; + } + uint8_t dl_vlan_pcp() { + return this->dl_vlan_pcp_; + } + uint16_t dl_type() { + return this->dl_type_; + } + uint8_t nw_tos() { + return this->nw_tos_; + } + uint8_t nw_proto() { + return this->nw_proto_; + } + IPAddress nw_src() { + return this->nw_src_; + } + IPAddress nw_dst() { + return this->nw_dst_; + } + uint16_t tp_src() { + return this->tp_src_; + } + uint16_t tp_dst() { + return this->tp_dst_; + } + + void wildcards(uint32_t wildcards); + void in_port(uint16_t in_port); + void dl_src(const EthAddress &dl_src); + void dl_dst(const EthAddress &dl_dst); + void dl_vlan(uint16_t dl_vlan); + void dl_vlan_pcp(uint8_t dl_vlan_pcp); + void dl_type(uint16_t dl_type); + void nw_tos(uint8_t nw_tos); + void nw_proto(uint8_t nw_proto); + void nw_src(const IPAddress &nw_src); + void nw_dst(const IPAddress &nw_dst); + void nw_src(const IPAddress &nw_src, uint32_t prefix); + void nw_dst(const IPAddress &nw_src, uint32_t prefix); + void tp_src(uint16_t tp_src); + void tp_dst(uint16_t tp_dst); +}; + +} //End of Namespace of10 +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/of10/openflow-10.h b/include/libfluid-msg/of10/openflow-10.h new file mode 100644 index 00000000..dc1ceb39 --- /dev/null +++ b/include/libfluid-msg/of10/openflow-10.h @@ -0,0 +1,889 @@ +/* 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. + */ + +/* OpenFlow: protocol between controller and datapath. */ + +#ifndef OF10OPENFLOW_OPENFLOW_H +#define OF10OPENFLOW_OPENFLOW_H 1 + +#include "../ofcommon/openflow-common.hh" + +namespace fluid_msg { + +namespace of10 { + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +const uint8_t OFP_VERSION = 0x01; + +/* Port numbering. Physical ports are numbered starting from 1. */ +enum ofp_port { + /* Maximum number of physical switch ports. */ + OFPP_FLUID_MAX = 0xff00, + + /* Fake output "ports". */ + OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This + virtual port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfff9, /* Perform actions in flow table. + NB: This can only be the destination + port for packet-out messages. */ + OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ + OFPP_FLUID_FLOOD = 0xfffb, /* All physical ports except input port and + those disabled by STP. */ + OFPP_ALL = 0xfffc, /* All physical ports except input port. */ + OFPP_FLUID_CONTROLLER = 0xfffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ + OFPP_NONE = 0xffff /* Not associated with a physical port. */ +}; + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ + OFPT_SET_CONFIG, /* Controller/switch message */ + + /* Asynchronous messages. */ + OFPT_PACKET_IN, /* Async message */ + OFPT_FLOW_REMOVED, /* Async message */ + OFPT_PORT_STATUS, /* Async message */ + + /* Controller command messages. */ + OFPT_PACKET_OUT, /* Controller/switch message */ + OFPT_FLOW_MOD, /* Controller/switch message */ + OFPT_PORT_MOD, /* Controller/switch message */ + + /* Statistics messages. */ + OFPT_STATS_REQUEST, /* Controller/switch message */ + OFPT_STATS_REPLY, /* Controller/switch message */ + + /* Barrier messages. */ + OFPT_BARRIER_REQUEST, /* Controller/switch message */ + OFPT_BARRIER_REPLY, /* Controller/switch message */ + + /* Queue Configuration messages. */ + OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ + +}; + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_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_fluid_header) == 8); + +/* OFPT_HELLO. This message has an empty body, but implementations must + * ignore any data included in the body, to allow for future extensions. */ +struct ofp_hello { + struct ofp_fluid_header header; +}; + +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1, /* Drop fragments. */ + OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3 +}; + +/* 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_STP = 1 << 3, /* 802.1d spanning tree. */ + OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_phy_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_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ + OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning + tree packets. */ + OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ + OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ + 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. */ + + /* The OFPPS_STP_* bits have no effect on switch operation. The + * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and + * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning + * tree. */ + OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ + OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ + OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ + OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ + OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ +}; + +/* Features of physical 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_COPPER = 1 << 7, /* Copper medium. */ + OFPPF_FIBER = 1 << 8, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 10, /* Pause. */ + OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ +}; + +/* Description of a physical port */ +struct ofp_phy_port { + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; + 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_fluid_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 pad[3]; /* Align to 64-bits. */ + + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ + + /* Port info.*/ + struct ofp_phy_port ports[0]; /* Port definitions. The number of ports + is inferred from the length field in + the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); + +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD, /* The port was added. */ + OFPPR_DELETE, /* The port was removed. */ + OFPPR_MODIFY /* Some attribute of the port has changed. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_fluid_header header; + uint8_t reason; /* One of OFPPR_*. */ + uint8_t pad[7]; /* Align to 64-bits. */ + struct ofp_phy_port desc; +}; +OFP_ASSERT(sizeof(struct ofp_port_status) == 64); + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_fluid_header header; + uint16_t port_no; + 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_phy_port struct. */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all + bits to prevent any action taking place. */ + uint8_t pad[4]; /* Pad to 64-bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); + +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH, /* No matching flow. */ + OFPR_ACTION /* Action explicitly output to controller. */ +}; + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_fluid_header header; + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint16_t in_port; /* Port on which frame was received. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t pad; + uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, + so the IP header is 32-bit aligned. The + amount of data is inferred from the length + field in the header. Because of padding, + offsetof(struct ofp_packet_in, data) == + sizeof(struct ofp_packet_in) - 2. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); + +enum ofp_action_type { + OFPAT_OUTPUT, /* Output to switch port. */ + OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ + OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ + OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ + OFPAT_SET_DL_SRC, /* Ethernet source address. */ + OFPAT_SET_DL_DST, /* Ethernet destination address. */ + OFPAT_SET_NW_SRC, /* IP source address. */ + OFPAT_SET_NW_DST, /* IP destination address. */ + OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ + OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ + OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ + OFPAT_ENQUEUE, /* Output to queue. */ + OFPAT_VENDOR = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. + * When the 'port' is the OFPP_FLUID_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.*/ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 8. */ + uint16_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_output) == 8); + +/* Action structure for OFPAT_SET_VLAN_VID. */ +struct ofp_action_vlan_vid { + uint16_t type; /* OFPAT_SET_VLAN_VID. */ + uint16_t len; /* Length is 8. */ + uint16_t vlan_vid; /* VLAN id. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); + +/* Action structure for OFPAT_SET_VLAN_PCP. */ +struct ofp_action_vlan_pcp { + uint16_t type; /* OFPAT_SET_VLAN_PCP. */ + uint16_t len; /* Length is 8. */ + uint8_t vlan_pcp; /* VLAN priority. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); + +/* Action structure for OFPAT_SET_DL_SRC/DST. */ +struct ofp_action_dl_addr { + uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ + uint16_t len; /* Length is 16. */ + uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); + +/* Action structure for OFPAT_SET_NW_SRC/DST. */ +struct ofp_action_nw_addr { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint32_t nw_addr; /* IP address. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); + +/* Action structure for OFPAT_SET_TP_SRC/DST. */ +struct ofp_action_tp_port { + uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint16_t tp_port; /* TCP/UDP port. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); + +/* Action structure for OFPAT_SET_NW_TOS. */ +struct ofp_action_nw_tos { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); + +/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ +struct ofp_action_enqueue { + uint16_t type; /* OFPAT_ENQUEUE. */ + uint16_t len; /* Len is 16. */ + uint16_t port; /* Port that queue belongs. Should + refer to a valid physical port + (i.e. < OFPP_FLUID_MAX) or OFPP_IN_PORT. */ + uint8_t pad[6]; /* Pad for 64-bit alignment. */ + uint32_t queue_id; /* Where to enqueue the packets. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); + +/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ +struct ofp_action_vendor_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t vendor; /* Vendor ID, which takes the same form + as in "struct ofp_vendor_header". */ +}; +OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); + +/* 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); + +const uint32_t OFP_NO_BUFFER = 0xffffffff; + +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_fluid_header header; + uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ + uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ + uint16_t actions_len; /* Size of action array in bytes. */ + struct ofp_action_header actions[0]; /* Actions. */ + /* uint8_t data[0]; *//* Packet data. The length is inferred + from the length field in the header. + (Only meaningful if buffer_id == -1.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); + +enum ofp_flow_mod_command { + OFPFC_ADD, /* New flow. */ + OFPFC_MODIFY, /* Modify all matching flows. */ + OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ + OFPFC_DELETE, /* Delete all matching flows. */ + OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ +}; + +/* Flow wildcards. */ +enum ofp_flow_wildcards { + OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ + OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ + OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ + OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ + OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ + OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ + OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ + OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ + + /* IP source address wildcard bit count. 0 is exact match, 1 ignores the + * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard + * the entire field. This is the *opposite* of the usual convention where + * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ + OFPFW_NW_SRC_SHIFT = 8, + OFPFW_NW_SRC_BITS = 6, + OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, + OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, + + /* IP destination address wildcard bit count. Same format as source. */ + OFPFW_NW_DST_SHIFT = 14, + OFPFW_NW_DST_BITS = 6, + OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, + OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, + + OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ + OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ + + /* Wildcard all fields. */ + OFPFW_ALL = ((1 << 22) - 1) +}; + +/* The wildcards for ICMP type and code fields use the transport source + * and destination port fields, respectively. */ +#define OFPFW_ICMP_TYPE OFPFW_TP_SRC +#define OFPFW_ICMP_CODE OFPFW_TP_DST + +/* Values below this cutoff are 802.3 packets and the two bytes + * following MAC addresses are used as a frame length. Otherwise, the + * two bytes are used as the Ethernet type. + */ +#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 + +/* Value of dl_type to indicate that the frame does not include an + * Ethernet type. + */ +#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * special conditions. All ones indicates that no VLAN id was set. + */ +#define OFP_VLAN_NONE 0xffff + +/* Fields to match against flows */ +struct ofp_match { + uint32_t wildcards; /* Wildcard fields. */ + uint16_t in_port; /* Input switch port. */ + uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t pad1[1]; /* Align to 64-bits */ + uint16_t dl_type; /* Ethernet frame type. */ + uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto; /* IP protocol or lower 8 bits of + * ARP opcode. */ + uint8_t pad2[2]; /* Align to 64-bits */ + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ +}; +OFP_ASSERT(sizeof(struct ofp_match) == 40); + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +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_EMERG = 1 << 2 /* Remark this is for emergency. */ +}; + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_fluid_header header; + struct ofp_match match; /* Fields to match */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + /* Flow actions. */ + uint16_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 -1). + Not meaningful for OFPFC_DELETE*. */ + uint16_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_NONE + indicates no restriction. */ + uint16_t flags; /* One of OFPFF_*. */ + struct ofp_action_header actions[0]; /* The action length is inferred + from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); + +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + OFPRR_DELETE /* Evicted by a DELETE flow mod. */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_fluid_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t pad[1]; /* Align to 32-bits. */ + + 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. */ + uint8_t pad2[2]; /* Align to 64-bits. */ + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); + +/* 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, /* Hello protocol failed. */ + OFPET_BAD_REQUEST, /* Request was not understood. */ + OFPET_BAD_ACTION, /* Error in action description. */ + OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ + OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ + OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ +}; + +/* ofp_fluid_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, /* No compatible version. */ + OFPHFC_EPERM /* Permissions error. */ +}; + +/* ofp_fluid_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, /* ofp_fluid_header.version not supported. */ + OFPBRC_BAD_TYPE, /* ofp_fluid_header.type not supported. */ + OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ + OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header + * or ofp_stats_request or ofp_stats_reply). */ + OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ + OFPBRC_EPERM, /* Permissions error. */ + OFPBRC_BAD_LEN, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ +}; + +/* ofp_fluid_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, /* Unknown action type. */ + OFPBAC_BAD_LEN, /* Length problem in actions. */ + OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ + OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ + OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ + OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ + OFPBAC_EPERM, /* Permissions error. */ + OFPBAC_TOO_MANY, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE /* Problem validating output queue. */ +}; + +/* ofp_fluid_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_ALL_TABLES_FULL, /* Flow not added because of full tables. */ + OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with + * CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM, /* Permissions error. */ + OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard + * timeout. */ + OFPFMFC_BAD_COMMAND, /* Unknown command. */ + OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in + * the order specified. */ +}; + +/* ofp_fluid_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, /* Specified port does not exist. */ + OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ +}; + +/* 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, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ + OFPQOFC_EPERM /* Permissions error. */ +}; + +enum ofp_stats_types { + /* Description of this OpenFlow switch. + * The request body is empty. + * The reply body is struct ofp_desc_stats. */ + OFPST_DESC, + + /* Individual flow statistics. + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ + OFPST_FLOW, + + /* Aggregate flow statistics. + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ + OFPST_AGGREGATE, + + /* Flow table statistics. + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ + OFPST_TABLE, + + /* Physical port statistics. + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ + OFPST_PORT, + + /* Queue statistics for a port + * The request body defines the port + * The reply body is an array of struct ofp_queue_stats */ + OFPST_QUEUE, + + /* Vendor extension. + * The request and reply bodies begin with a 32-bit vendor ID, which takes + * the same form as in "struct ofp_vendor_header". The request and reply + * bodies are otherwise vendor-defined. */ + OFPST_VENDOR = 0xffff +}; + +struct ofp_stats_request { + struct ofp_fluid_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ + uint8_t body[0]; /* Body of the request. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); + +enum ofp_stats_reply_flags { + OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_stats_reply { + struct ofp_fluid_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REPLY_* flags. */ + uint8_t body[0]; /* Body of the reply. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); + +/* Body for ofp_stats_request of type OFPST_FLOW. */ +struct ofp_flow_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); + +/* Body of reply to OFPST_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; + struct ofp_match match; /* Description of fields. */ + 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. Only meaningful + when this is not an exact-match 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_action_header actions[0]; /* Actions. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); + +/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ +struct ofp_aggregate_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); + +/* Body of reply to OFPST_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); + +/* Body of reply to OFPST_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. */ + char name[OFP_FLUID_MAX_TABLE_NAME_LEN]; + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + uint32_t max_entries; /* Max number of entries supported. */ + 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) == 64); + +/* Body for ofp_stats_request of type OFPST_PORT. */ +struct ofp_port_stats_request { + uint16_t port_no; /* OFPST_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_NONE). */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* Body of reply to OFPST_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint16_t port_no; + uint8_t pad[6]; /* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); + +/* Vendor extension. */ +struct ofp_vendor_header { + struct ofp_fluid_header header; /* Type OFPT_VENDOR. */ + uint32_t vendor; /* Vendor ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by OpenFlow + * consortium. */ + /* Vendor-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); + +enum ofp_queue_properties { + OFPQT_NONE = 0, /* No property defined for queue (default). */ + OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ +/* Other types should be added here + * (i.e. max rate, precedence, etc). */ +}; + +/* 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_queue_prop_min_rate) == 16); + +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[2]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_fluid_header header; + uint16_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_FLUID_MAX) */ + uint8_t pad[2]; /* 32-bit alignment. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); + +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_fluid_header header; + uint16_t port; + uint8_t pad[6]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); + +struct ofp_queue_stats_request { + uint16_t port_no; /* All ports if OFPT_ALL. */ + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* All queues if OFPQ_FLUID_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); + +struct ofp_queue_stats { + uint16_t port_no; + uint8_t pad[2]; /* Align to 32-bits. */ + 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); + +} + +} //End of namespace fluid_msg +#endif /* openflow/openflow.h */ diff --git a/include/libfluid-msg/of10msg.hh b/include/libfluid-msg/of10msg.hh new file mode 100644 index 00000000..ce2176b3 --- /dev/null +++ b/include/libfluid-msg/of10msg.hh @@ -0,0 +1,880 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF10MSG_H +#define OF10MSG_H 1 + +#include "ofcommon/msg.hh" +#include "of10/of10common.hh" +#include "of10/of10action.hh" + +/** + Classes for creating and parsing OpenFlow messages. + */ +namespace fluid_msg { + +/** + Classes for creating and parsing OpenFlow 1.0 messages. + */ +namespace of10 { + +/** + OpenFlow 1.0 OFPT_HELLO message. + */ +class Hello: public OFMsg { +public: + Hello(); + Hello(uint32_t xid); + ~Hello() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_ERROR message. + */ +class Error: public ErrorCommon { +public: + Error(); + Error(uint32_t xid, uint16_t err_type, uint16_t code); + Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len); + ~Error() { + } +}; + +/** + OpenFlow 1.0 OFPT_ECHO_REQUEST message. + */ +class EchoRequest: public EchoCommon { +public: + EchoRequest() + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REQUEST) { + } + EchoRequest(uint32_t xid); + ~EchoRequest() { + } +}; + +/** + OpenFlow 1.0 OFPT_ECHO_REPLY message. + */ +class EchoReply: public EchoCommon { +public: + EchoReply() + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REPLY) { + } + EchoReply(uint32_t xid); + ~EchoReply() { + } +}; + +/** + OpenFlow 1.0 OFPT_VENDOR message. + Vendor messages should inherit from this class. + */ +class Vendor: public OFMsg { +protected: + uint32_t vendor_; +public: + Vendor(); + Vendor(uint32_t xid, uint32_t vendor); + ~Vendor() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPT_FEATURES_REQUEST message. + */ +class FeaturesRequest: public OFMsg { +public: + FeaturesRequest(); + FeaturesRequest(uint32_t xid); + ~FeaturesRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_FEATURES_REPLY message. + */ +class FeaturesReply: public FeaturesReplyCommon { +private: + uint32_t actions_; + std::vector ports_; +public: + FeaturesReply(); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint32_t capabilities, uint32_t actions); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint32_t capabilities, uint32_t actions, + std::vector ports); + bool operator==(const FeaturesReply &other) const; + bool operator!=(const FeaturesReply &other) const; + ~FeaturesReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t actions() { + return this->actions_; + } + std::vector ports() { + return this->ports_; + } + void actions(uint32_t actions) { + this->actions_ = actions; + } + void ports(std::vector ports); + size_t ports_length(); + void add_port(of10::Port port); +}; + +/** + OpenFlow 1.0 OFPT_GET_CONFIG_REQUEST message. + */ +class GetConfigRequest: public OFMsg { +public: + GetConfigRequest(); + GetConfigRequest(uint32_t xid); + ~GetConfigRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPT_GET_CONFIG_REPLY message. + */ +class GetConfigReply: public SwitchConfigCommon { +public: + GetConfigReply(); + GetConfigReply(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~GetConfigReply() { + } +}; + +/** + OpenFlow 1.0 OFPT_SET_CONFIG message. + */ +class SetConfig: public SwitchConfigCommon { +public: + SetConfig(); + SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~SetConfig() { + } +}; + +/** + OpenFlow 1.0 OFPT_FLOW_MOD message. + */ +class FlowMod: public FlowModCommon { +private: + uint16_t command_; + uint16_t out_port_; + of10::Match match_; + ActionList actions_; +public: + FlowMod(); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, + of10::Match match); + FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, + of10::Match match, ActionList actions); + ~FlowMod() { + } + bool operator==(const FlowMod &other) const; + bool operator!=(const FlowMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command(){ + return this->command_; + } + of10::Match match() { + return this->match_; + } + ActionList actions() { + return this->actions_; + } + uint16_t out_port() { + return this->out_port_; + } + void command(uint16_t command){ + this->command_ = command; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } + void match(const of10::Match& match) { + this->match_ = match; + } + void actions(const ActionList &actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +/** + OpenFlow 1.0 OFPT_PACKET_OUT message. + */ +class PacketOut: public PacketOutCommon { +private: + uint16_t in_port_; +public: + PacketOut(); + PacketOut(uint32_t xid, uint32_t buffer_id, uint16_t in_port); + ~PacketOut() { + } + bool operator==(const PacketOut &other) const; + bool operator!=(const PacketOut &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t in_port() { + return this->in_port_; + } + void in_port(uint16_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.0 OFPT_PACKET_IN message. + */ +class PacketIn: public PacketInCommon { +private: + uint16_t in_port_; +public: + PacketIn(); + PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t in_port, + uint16_t total_len, uint8_t reason); + ~PacketIn() { + } + bool operator==(const PacketIn &other) const; + bool operator!=(const PacketIn &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t in_port() { + return this->in_port_; + } + void in_port(uint16_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.0 OFPT_FLOW_REMOVED message. + */ +class FlowRemoved: public FlowRemovedCommon { +private: + of10::Match match_; +public: + FlowRemoved(); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count, + of10::Match match); + ~FlowRemoved() { + } + bool operator==(const FlowRemoved &other) const; + bool operator!=(const FlowRemoved &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + void match(of10::Match match) { + this->match_ = match; + } +}; + +/** + OpenFlow 1.0 OFPT_PORT_STATUS message. + */ +class PortStatus: public PortStatusCommon { +private: + of10::Port desc_; +public: + PortStatus(); + PortStatus(uint32_t xid, uint8_t reason, of10::Port desc); + ~PortStatus() { + } + bool operator==(const PortStatus &other) const; + bool operator!=(const PortStatus &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Port desc() { + return this->desc_; + } + void desc(of10::Port desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.0 OFPT_PORT_MOD message. + */ +class PortMod: public PortModCommon { +private: + uint16_t port_no_; +public: + PortMod(); + PortMod(uint32_t xid, uint16_t port_no, EthAddress hw_addr, uint32_t config, + uint32_t mask, uint32_t advertise); + ~PortMod() { + } + bool operator==(const PortMod &other) const; + bool operator!=(const PortMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.0 OFPT_STATS_REQUEST message header. Stats request + messages should inherit from this class. + */ +class StatsRequest: public OFMsg { +protected: + uint16_t stats_type_; + uint16_t flags_; +public: + StatsRequest(); + StatsRequest(uint16_t); + StatsRequest(uint32_t xid, uint16_t type, uint16_t flags); + ~StatsRequest() { + } + bool operator==(const StatsRequest &other) const; + bool operator!=(const StatsRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t stats_type() { + return this->stats_type_; + } + uint16_t flags() { + return this->flags_; + } + void stats_type(uint16_t type) { + this->stats_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.0 OFPT_STATS_REPLY message header. Stats reply + messages should inherit from this class. + */ +class StatsReply: public OFMsg { +protected: + uint16_t stats_type_; + uint16_t flags_; +public: + StatsReply(); + StatsReply(uint16_t type); + StatsReply(uint32_t xid, uint16_t type, uint16_t flags); + ~StatsReply() { + } + bool operator==(const StatsReply &other) const; + bool operator!=(const StatsReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t stats_type() { + return this->stats_type_; + } + uint16_t flags() { + return this->flags_; + } + void stats_type(uint16_t type) { + this->stats_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.0 OFPST_DESC multipart request. + */ +class StatsRequestDesc: public StatsRequest { +public: + StatsRequestDesc(); + StatsRequestDesc(uint32_t xid, uint16_t flags); + ~StatsRequestDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPST_DESC multipart reply. + */ +class StatsReplyDesc: public StatsReply { +private: + SwitchDesc desc_; +public: + StatsReplyDesc(); + StatsReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc); + StatsReplyDesc(uint32_t xid, uint16_t flags, std::string mfr_desc, + std::string hw_desc, std::string sw_desc, std::string serial_num, + std::string dp_desc); + ~StatsReplyDesc() { + } + bool operator==(const StatsReplyDesc &other) const; + bool operator!=(const StatsReplyDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + SwitchDesc desc() { + return this->desc_; + } + void desc(SwitchDesc desc); +}; + +/** + OpenFlow 1.0 OFPST_FLOW multipart request. + */ +class StatsRequestFlow: public StatsRequest { +private: + of10::Match match_; + uint8_t table_id_; + uint16_t out_port_; +public: + StatsRequestFlow(); + StatsRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint16_t out_port); + StatsRequestFlow(uint32_t xid, uint16_t flags, of10::Match match, + uint8_t table_id, uint16_t out_port); + virtual ~StatsRequestFlow() { + } + bool operator==(const StatsRequestFlow &other) const; + bool operator!=(const StatsRequestFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint16_t out_port() { + return this->out_port_; + } + void match(of10::Match match) { + this->match_ = match; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } +}; + +/** + OpenFlow 1.0 OFPST_FLOW multipart reply. + */ +class StatsReplyFlow: public StatsReply { +private: + std::vector flow_stats_; +public: + StatsReplyFlow(); + StatsReplyFlow(uint32_t xid, uint16_t flags); + StatsReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats); + virtual ~StatsReplyFlow() { + } + bool operator==(const StatsReplyFlow &other) const; + bool operator!=(const StatsReplyFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector flow_stats() { + return this->flow_stats_; + } + void flow_stats(std::vector flow_stats); + void add_flow_stats(of10::FlowStats); +}; + +/** + OpenFlow 1.0 OFPST_AGGREGATE multipart request. + */ +class StatsRequestAggregate: public StatsRequest { +private: + of10::Match match_; + uint8_t table_id_; + uint16_t out_port_; +public: + StatsRequestAggregate(); + StatsRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint16_t out_port); + StatsRequestAggregate(uint32_t xid, uint16_t flags, of10::Match match, + uint8_t table_id, uint16_t out_port); + ~StatsRequestAggregate() { + } + bool operator==(const StatsRequestAggregate &other) const; + bool operator!=(const StatsRequestAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of10::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint16_t out_port() { + return this->out_port_; + } + void match(of10::Match match) { + this->match_ = match; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint16_t out_port) { + this->out_port_ = out_port; + } +}; + +/** + OpenFlow 1.0 OFPST_AGGREGATE multipart reply. + */ +class StatsReplyAggregate: public StatsReply { +private: + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t flow_count_; +public: + StatsReplyAggregate(); + StatsReplyAggregate(uint32_t xid, uint16_t flags, uint64_t packet_count, + uint64_t byte_count, uint32_t flow_count); + ~StatsReplyAggregate() { + } + bool operator==(const StatsReplyAggregate &other) const; + bool operator!=(const StatsReplyAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t flow_count() { + return this->flow_count_; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void flow_count(uint32_t flow_count) { + this->flow_count_ = flow_count; + } +}; + +/** + OpenFlow 1.0 OFPST_TABLE multipart request. + */ +class StatsRequestTable: public StatsRequest { +public: + StatsRequestTable(); + StatsRequestTable(uint32_t xid, uint16_t flags); + ~StatsRequestTable() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.0 OFPST_TABLE multipart reply. + */ +class StatsReplyTable: public StatsReply { +private: + std::vector table_stats_; +public: + StatsReplyTable(); + StatsReplyTable(uint32_t xid, uint16_t flags); + StatsReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats); + ~StatsReplyTable() { + } + bool operator==(const StatsReplyTable &other) const; + bool operator!=(const StatsReplyTable &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_stats() { + return this->table_stats_; + } + void table_stats(std::vector table_stats); + void add_table_stat(of10::TableStats stat); +}; + +/** + OpenFlow 1.0 OFPST_PORT_STATS multipart request. + */ +class StatsRequestPort: public StatsRequest { +private: + uint16_t port_no_; +public: + StatsRequestPort(); + StatsRequestPort(uint32_t xid, uint16_t flags, uint16_t port_no); + ~StatsRequestPort() { + } + bool operator==(const StatsRequestPort &other) const; + bool operator!=(const StatsRequestPort &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.0 OFPST_PORT_STATS multipart reply. + */ +class StatsReplyPort: public StatsReply { +private: + std::vector port_stats_; +public: + StatsReplyPort(); + StatsReplyPort(uint32_t xid, uint16_t flags); + StatsReplyPort(uint32_t xid, uint16_t flags, + std::vector port_stats); + ~StatsReplyPort() { + } + bool operator==(const StatsReplyPort &other) const; + bool operator!=(const StatsReplyPort &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector port_stats() { + return this->port_stats_; + } + void port_stats(std::vector port_stats); + void add_port_stat(of10::PortStats stat); +}; + +/** + OpenFlow 1.0 OFPST_QUEUE multipart request. + */ +class StatsRequestQueue: public StatsRequest { +private: + uint16_t port_no_; + uint32_t queue_id_; +public: + StatsRequestQueue(); + StatsRequestQueue(uint32_t xid, uint16_t flags, uint16_t port_no, + uint32_t queue_id); + ~StatsRequestQueue() { + } + bool operator==(const StatsRequestQueue &other) const; + bool operator!=(const StatsRequestQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port_no(uint16_t port_no) { + this->port_no_ = port_no; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +/** + OpenFlow 1.0 OFPST_QUEUE multipart reply. + */ +class StatsReplyQueue: public StatsReply { +private: + std::vector queue_stats_; +public: + StatsReplyQueue(); + StatsReplyQueue(uint32_t xid, uint16_t flags); + StatsReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats); + ~StatsReplyQueue() { + } + bool operator==(const StatsReplyQueue &other) const; + bool operator!=(const StatsReplyQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->queue_stats_; + } + void queue_stats(std::vector queue_stats_); + void add_queue_stat(of10::QueueStats stat); +}; + +/** + OpenFlow 1.0 OFPST_VENDOR stats request. + Vendor stats request messages should inherit from this class. + */ +class StatsRequestVendor: public StatsRequest { +protected: + uint32_t vendor_; +public: + StatsRequestVendor(); + StatsRequestVendor(uint32_t xid, uint16_t flags, uint32_t vendor); + virtual ~StatsRequestVendor() { + } + bool operator==(const StatsRequestVendor &other) const; + bool operator!=(const StatsRequestVendor &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPST_VENDOR stats reply. + Vendor stats reply messages should inherit from this class. + */ +class StatsReplyVendor: public StatsReply { +protected: + uint32_t vendor_; +public: + StatsReplyVendor(); + StatsReplyVendor(uint32_t xid, uint16_t flags, uint32_t vendor); + virtual ~StatsReplyVendor() { + } + bool operator==(const StatsReplyVendor &other) const; + bool operator!=(const StatsReplyVendor &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t vendor() { + return this->vendor_; + } + void vendor(uint32_t vendor) { + this->vendor_ = vendor; + } +}; + +/** + OpenFlow 1.0 OFPT_QUEUE_GET_CONFIG_REQUEST message. + */ +class QueueGetConfigRequest: public OFMsg { +private: + uint16_t port_; +public: + QueueGetConfigRequest(); + QueueGetConfigRequest(uint32_t xid, uint16_t port); + ~QueueGetConfigRequest() { + } + bool operator==(const QueueGetConfigRequest &other) const; + bool operator!=(const QueueGetConfigRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + void port(uint16_t port) { + this->port_ = port; + } +}; + +/** + OpenFlow 1.0 OFPT_QUEUE_GET_CONFIG_REPLY message. + */ +class QueueGetConfigReply: public OFMsg { +private: + uint16_t port_; + std::list queues_; +public: + QueueGetConfigReply(); + QueueGetConfigReply(uint32_t xid, uint16_t port); + QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues); + ~QueueGetConfigReply() { + } + bool operator==(const QueueGetConfigReply &other) const; + bool operator!=(const QueueGetConfigReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port() { + return this->port_; + } + std::list queues() { + return this->queues_; + } + void port(uint32_t port) { + this->port_ = port; + } + void queues(std::list queues); + void add_queue(PacketQueue queue); + size_t queues_len(); +}; + +/** + OpenFlow 1.0 OFPT_BARRIER_REQUEST message + */ +class BarrierRequest: public OFMsg { +public: + BarrierRequest(); + BarrierRequest(uint32_t xid); + ~BarrierRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.0 OFPT_BARRIER_REPLY message*/ +class BarrierReply: public OFMsg { +public: + BarrierReply(); + BarrierReply(uint32_t xid); + ~BarrierReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +} //end of namespace of10 +} //End of namespace fluid_msg + +#endif + diff --git a/include/libfluid-msg/of13/of13action.hh b/include/libfluid-msg/of13/of13action.hh new file mode 100644 index 00000000..5ea63717 --- /dev/null +++ b/include/libfluid-msg/of13/of13action.hh @@ -0,0 +1,419 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF13ACTION_H +#define OF13ACTION_H + +#include "../ofcommon/action.hh" +#include "of13match.hh" + +namespace fluid_msg { + +namespace of13 { + +class OutputAction: public Action { +private: + uint32_t port_; + uint16_t max_len_; + const uint16_t set_order_; +public: + OutputAction(); + OutputAction(uint32_t port, uint16_t max_len); + ~OutputAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual OutputAction* clone() { + return new OutputAction(*this); + } + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } + uint16_t max_len() { + return this->max_len_; + } + void max_len(uint16_t max_len) { + this->max_len_ = max_len; + } +}; + +class CopyTTLOutAction: public Action { +private: + const uint16_t set_order_; +public: + CopyTTLOutAction(); + ~CopyTTLOutAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual CopyTTLOutAction* clone() { + return new CopyTTLOutAction(*this); + } +}; + +class CopyTTLInAction: public Action { +private: + const uint16_t set_order_; +public: + CopyTTLInAction(); + ~CopyTTLInAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual CopyTTLInAction* clone() { + return new CopyTTLInAction(*this); + } +}; + +class SetMPLSTTLAction: public Action { +private: + uint8_t mpls_ttl_; + const uint16_t set_order_; +public: + SetMPLSTTLAction(); + SetMPLSTTLAction(uint8_t mpls_ttl); + ~SetMPLSTTLAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t mpls_ttl() { + return this->mpls_ttl_; + } + void mpls_ttl(uint8_t mpls_ttl) { + this->mpls_ttl_ = mpls_ttl; + } + virtual SetMPLSTTLAction* clone() { + return new SetMPLSTTLAction(*this); + } +}; + +class DecMPLSTTLAction: public Action { +private: + const uint16_t set_order_; +public: + DecMPLSTTLAction(); + ~DecMPLSTTLAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual DecMPLSTTLAction* clone() { + return new DecMPLSTTLAction(*this); + } +}; + +class PushVLANAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushVLANAction(); + PushVLANAction(uint16_t ethertype); + ~PushVLANAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushVLANAction* clone() { + return new PushVLANAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopVLANAction: public Action { +private: + const uint16_t set_order_; +public: + PopVLANAction(); + ~PopVLANAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopVLANAction* clone() { + return new PopVLANAction(*this); + } +}; + +class PushMPLSAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushMPLSAction(); + PushMPLSAction(uint16_t ethertype); + ~PushMPLSAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushMPLSAction* clone() { + return new PushMPLSAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopMPLSAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PopMPLSAction(); + PopMPLSAction(uint16_t ethertype); + ~PopMPLSAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopMPLSAction* clone() { + return new PopMPLSAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class SetQueueAction: public Action { +private: + uint32_t queue_id_; + const uint16_t set_order_; +public: + SetQueueAction(); + SetQueueAction(uint32_t queue_id); + ~SetQueueAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetQueueAction* clone() { + return new SetQueueAction(*this); + } + uint32_t queue_id() { + return this->queue_id_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +class GroupAction: public Action { +private: + uint32_t group_id_; + const uint16_t set_order_; +public: + GroupAction(); + GroupAction(uint32_t group_id); + ~GroupAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual GroupAction* clone() { + return new GroupAction(*this); + } + uint32_t group_id() { + return this->group_id_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } +}; + +class SetNWTTLAction: public Action { +private: + uint8_t nw_ttl_; + const uint16_t set_order_; +public: + SetNWTTLAction(); + SetNWTTLAction(uint8_t nw_ttl); + ~SetNWTTLAction() { + } + ; + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetNWTTLAction* clone() { + return new SetNWTTLAction(*this); + } + uint8_t nw_ttl() { + return this->nw_ttl_; + } + void nw_ttl(uint8_t nw_ttl) { + this->nw_ttl_ = nw_ttl; + } +}; + +class DecNWTTLAction: public Action { +private: + const uint16_t set_order_; +public: + DecNWTTLAction(); + ~DecNWTTLAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual DecNWTTLAction* clone() { + return new DecNWTTLAction(*this); + } +}; + +class SetFieldAction: public Action { +private: + OXMTLV* field_; + const uint16_t set_order_; +public: + SetFieldAction(); + SetFieldAction(OXMTLV* field); + SetFieldAction(const SetFieldAction &other); + ~SetFieldAction(); + virtual bool equals(const Action & other); + SetFieldAction& operator=(SetFieldAction other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual SetFieldAction* clone() { + return new SetFieldAction(*this); + } + OXMTLV* field(); + void field(OXMTLV* field); + friend void swap(SetFieldAction& first, SetFieldAction& second); +}; + +class PushPBBAction: public Action { +private: + uint16_t ethertype_; + const uint16_t set_order_; +public: + PushPBBAction(); + PushPBBAction(uint16_t ethertype); + ~PushPBBAction() { + } + virtual bool equals(const Action & other); + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PushPBBAction* clone() { + return new PushPBBAction(*this); + } + uint16_t ethertype() { + return this->ethertype_; + } + void ethertype(uint16_t ethertype) { + this->ethertype_ = ethertype; + } +}; + +class PopPBBAction: public Action { +private: + const uint16_t set_order_; +public: + PopPBBAction(); + ~PopPBBAction() { + } + uint16_t set_order() const { + return this->set_order_; + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual PopPBBAction* clone() { + return new PopPBBAction(*this); + } +}; + +class ExperimenterAction: public Action { +protected: + uint32_t experimenter_; +public: + ExperimenterAction(); + ExperimenterAction(uint32_t experimenter); + ~ExperimenterAction() { + } + virtual bool equals(const Action & other); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + virtual ExperimenterAction* clone() { + return new ExperimenterAction(*this); + } + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/of13common.hh b/include/libfluid-msg/of13/of13common.hh new file mode 100644 index 00000000..75abe88b --- /dev/null +++ b/include/libfluid-msg/of13/of13common.hh @@ -0,0 +1,784 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF13OPENFLOW_COMMON_H +#define OF13OPENFLOW_COMMON_H 1 + +#include +#include + +#include "../ofcommon/common.hh" +#include "../util/util.h" +#include "openflow-13.h" +#include "of13action.hh" +#include "of13instruction.hh" + +namespace fluid_msg { + +namespace of13 { + +class HelloElem { +protected: + uint16_t type_; + uint16_t length_; +public: + HelloElem() { + } + HelloElem(uint16_t type, uint16_t length); + ~HelloElem() { + } + bool operator==(const HelloElem &other) const; + bool operator!=(const HelloElem &other) const; + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } +}; + +class HelloElemVersionBitmap: public HelloElem { +private: + std::list bitmaps_; +public: + HelloElemVersionBitmap() + : HelloElem(of13::OFPHET_VERSIONBITMAP, + sizeof(struct of13::ofp_hello_elem_versionbitmap)) { + } + HelloElemVersionBitmap(std::list bitmap); + bool operator==(const HelloElemVersionBitmap &other) const; + bool operator!=(const HelloElemVersionBitmap &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t *data); + std::list bitmaps() { + return this->bitmaps_; + } + void bitmaps(std::list bitmaps) { + this->bitmaps_ = bitmaps; + } + void add_bitmap(uint32_t bitmap); +}; + +class Port: public PortCommon { +private: + uint32_t port_no_; + uint32_t curr_speed_; + uint32_t max_speed_; +public: + Port(); + Port(uint32_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer, uint32_t curr_speed, + uint32_t max_speed); + ~Port() { + } + bool operator==(const Port &other) const; + bool operator!=(const Port &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t curr_speed() { + return this->curr_speed_; + } + uint32_t max_speed() { + return this->max_speed_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void curr_speed(uint32_t curr_speed) { + this->curr_speed_ = curr_speed; + } + void max_speed(uint32_t max_speed) { + this->max_speed_ = max_speed; + } +}; + +class QueuePropMinRate: public QueuePropRate { +public: + QueuePropMinRate() + : QueuePropRate(of13::OFPQT_MIN_RATE) { + } + QueuePropMinRate(uint16_t rate); + ~QueuePropMinRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMinRate* clone() { + return new QueuePropMinRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class QueuePropMaxRate: public QueuePropRate { +public: + QueuePropMaxRate() + : QueuePropRate(of13::OFPQT_MAX_RATE) { + } + QueuePropMaxRate(uint16_t rate); + ~QueuePropMaxRate() { + } + virtual bool equals(const QueueProperty & other); + virtual QueuePropMaxRate* clone() { + return new QueuePropMaxRate(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class QueueExperimenter: public QueueProperty { +protected: + uint32_t experimenter_; +public: + QueueExperimenter() { + } + QueueExperimenter(uint32_t experimenter); + ~QueueExperimenter() { + } + virtual QueueExperimenter* clone() { + return new QueueExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t get_experimenter() { + return this->experimenter_; + } + void set_experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +/* Queue description*/ +class PacketQueue: public PacketQueueCommon { +private: + uint32_t port_; +public: + PacketQueue(); + PacketQueue(uint32_t queue_id, uint32_t port); + PacketQueue(uint32_t queue_id, uint32_t port, QueuePropertyList properties); + ~PacketQueue() { + } + bool operator==(const PacketQueue &other) const; + bool operator!=(const PacketQueue &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } +}; + +class Bucket { +private: + uint16_t length_; + uint16_t weight_; + uint32_t watch_port_; + uint32_t watch_group_; + ActionSet actions_; +public: + Bucket(); + Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group); + Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group, + ActionSet actions); + ~Bucket() { + } + bool operator==(const Bucket &other) const; + bool operator!=(const Bucket &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t len() { + return this->length_; + } + uint16_t weight() { + return this->weight_; + } + uint32_t watch_port() { + return this->watch_port_; + } + uint32_t watch_group() { + return this->watch_group_; + } + ActionSet get_actions() { + return this->actions_; + } + void weight(uint16_t weight) { + this->weight_ = weight; + } + void watch_port(uint32_t watch_port) { + this->watch_port_ = watch_port; + } + void watch_group(uint32_t watch_group) { + this->watch_group_ = watch_group; + } + void actions(ActionSet actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class FlowStats: public FlowStatsCommon { +private: + uint16_t flags_; + of13::Match match_; + InstructionSet instructions_; +public: + FlowStats(); + FlowStats(uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t priority, uint16_t idle_timeout, uint16_t hard_timeout, + uint16_t flags, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count); + ~FlowStats() { + } + bool operator==(const FlowStats &other) const; + bool operator!=(const FlowStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t get_flags() { + return this->flags_; + } + void set_flags(uint16_t flags) { + this->flags_ = flags; + } + void match(of13::Match match); + of13::Match match() { + return this->match_; + } + OXMTLV * get_oxm_field(uint8_t field); + void instructions(InstructionSet instructions); + void add_instruction(Instruction* inst); + InstructionSet instructions() { + return this->instructions_; + } +}; + +class TableStats: public TableStatsCommon { +public: + TableStats(); + TableStats(uint8_t table_id, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count); + ~TableStats() { + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class PortStats: public PortStatsCommon { +private: + uint32_t port_no_; + uint32_t duration_sec_; + uint32_t duration_nsec_; +public: + PortStats(); + PortStats(uint32_t port_no, struct port_rx_tx_stats tx_stats, + struct port_err_stats err_stats, uint64_t collisions, + uint32_t duration_sec, uint32_t duration_nsec); + ~PortStats() { + } + bool operator==(const PortStats &other) const; + bool operator!=(const PortStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } +}; + +class QueueStats: public QueueStatsCommon { +private: + uint32_t port_no_; + uint32_t duration_sec_; + uint32_t duration_nsec_; +public: + QueueStats(); + QueueStats(uint32_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors, uint32_t duration_sec, + uint32_t duration_nsec); + ~QueueStats() { + } + bool operator==(const QueueStats &other) const; + bool operator!=(const QueueStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t port_no() { + return this->port_no_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } +}; + +class BucketStats { +private: + uint64_t packet_count_; + uint64_t byte_count_; +public: + BucketStats(); + BucketStats(uint64_t packet_count, uint64_t byte_count); + ~BucketStats() { + } + bool operator==(const BucketStats &other) const; + bool operator!=(const BucketStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } +}; + +class GroupStats { +private: + uint16_t length_; + uint32_t group_id_; + uint32_t ref_count_; + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + std::vector bucket_stats_; +public: + GroupStats() + : length_(sizeof(struct of13::ofp_group_stats)) { + } + GroupStats(uint32_t group_id, uint32_t ref_count, uint64_t packet_count, + uint64_t byte_count, uint32_t duration_sec, uint32_t duration_nsec); + GroupStats(uint32_t group_id, uint32_t ref_count, uint64_t packet_count, + uint64_t byte_count, uint32_t duration_sec, uint32_t duration_nsec, + std::vector bucket_stats); + ~GroupStats() { + } + bool operator==(const GroupStats &other) const; + bool operator!=(const GroupStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint32_t group_id() { + return this->group_id_; + } + uint32_t ref_count() { + return this->ref_count_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void ref_count(uint32_t ref_count) { + this->ref_count_ = ref_count; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint64_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void bucket_stats(std::vector bucket_stats); + void add_bucket_stat(BucketStats stat); +}; + +class GroupDesc { +private: + uint16_t length_; + uint8_t type_; + uint32_t group_id_; + std::vector buckets_; +public: + GroupDesc() + : length_(sizeof(struct of13::ofp_group_desc_stats)) { + } + GroupDesc(uint8_t type, uint32_t group_id); + GroupDesc(uint8_t type, uint32_t group_id, + std::vector buckets); + ~GroupDesc() { + } + bool operator==(const GroupDesc &other) const; + bool operator!=(const GroupDesc &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint8_t type() { + return this->type_; + } + uint32_t group_id() { + return this->group_id_; + } + std::vector buckets() { + return this->buckets_; + } + void type(uint8_t type) { + this->type_ = type; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void buckets(std::vector buckets); + void add_bucket(Bucket bucket); + size_t buckets_len(); +}; + +class GroupFeatures { +private: + uint32_t types_; + uint32_t capabilities_; + uint32_t max_groups_[4]; + uint32_t actions_[4]; +public: + GroupFeatures() { + } + GroupFeatures(uint32_t types, uint32_t capabilities, uint32_t max_groups[4], + uint32_t actions[4]); + ~GroupFeatures() { + } + bool operator==(const GroupFeatures &other) const; + bool operator!=(const GroupFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t types() { + return this->types_; + } + uint32_t capabilities() { + return this->capabilities_; + } + uint32_t* max_groups() { + return this->max_groups_; + } + uint32_t* actions() { + return this->actions_; + } + void types(uint32_t types) { + this->types_ = types; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } + void max_groups(uint32_t max_groups[4]) { + memcpy(this->max_groups_, max_groups, 16); + } + void actions(uint32_t actions[4]) { + memcpy(this->actions_, actions, 16); + } +}; + +class TableFeatureProp { +protected: + uint16_t type_; + uint16_t length_; + uint8_t padding_; +public: + TableFeatureProp() + : length_(sizeof(struct ofp_table_feature_prop_header)), + padding_(4) { + } + TableFeatureProp(uint16_t type); + virtual ~TableFeatureProp() { + } + virtual bool equals(const TableFeatureProp & other); + virtual bool operator==(const TableFeatureProp &other) const; + virtual bool operator!=(const TableFeatureProp &other) const; + virtual TableFeatureProp* clone() { + return new TableFeatureProp(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + uint8_t padding() { + return this->padding_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static bool delete_all(TableFeatureProp * prop) { + delete prop; + return true; + } +}; + +class TableFeaturePropInstruction: public TableFeatureProp { +private: + std::vector instruction_ids_; +public: + TableFeaturePropInstruction() + : TableFeatureProp() { + } + TableFeaturePropInstruction(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropInstruction(uint16_t type, + std::vector instruction_ids); + ~TableFeaturePropInstruction() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropInstruction* clone() { + return new TableFeaturePropInstruction(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector instruction_ids() { + return this->instruction_ids_; + } + void instruction_ids(std::vector instruction_ids); +}; + +class TableFeaturePropNextTables: public TableFeatureProp { +private: + std::vector next_table_ids_; +public: + TableFeaturePropNextTables() + : TableFeatureProp() { + } + TableFeaturePropNextTables(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropNextTables(uint16_t type, + std::vector next_table_ids); + ~TableFeaturePropNextTables() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropNextTables* clone() { + return new TableFeaturePropNextTables(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector next_table_ids() { + return this->next_table_ids_; + } + void table_ids(std::vector table_ids); +}; + +class TableFeaturePropActions: public TableFeatureProp { +private: + std::vector action_ids_; +public: + TableFeaturePropActions() + : TableFeatureProp() { + } + TableFeaturePropActions(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropActions(uint16_t type, std::vector action_ids); + ~TableFeaturePropActions() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropActions* clone() { + return new TableFeaturePropActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector action_ids() { + return this->action_ids_; + } + void action_ids(std::vector action_ids); +}; + +class TableFeaturePropOXM: public TableFeatureProp { +private: + std::vector oxm_ids_; +public: + TableFeaturePropOXM() + : TableFeatureProp() { + } + TableFeaturePropOXM(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropOXM(uint16_t type, std::vector oxm_ids); + ~TableFeaturePropOXM() { + } + virtual bool equals(const TableFeatureProp & other); + virtual TableFeaturePropOXM* clone() { + return new TableFeaturePropOXM(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + void oxm_ids(std::vector oxm_ids); +}; + +class TableFeaturePropExperimenter: public TableFeatureProp { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + TableFeaturePropExperimenter() + : TableFeatureProp() { + } + TableFeaturePropExperimenter(uint16_t type) + : TableFeatureProp(type) { + } + TableFeaturePropExperimenter(uint16_t type, uint32_t experimenter, + uint32_t exp_type); + ~TableFeaturePropExperimenter() { + } + virtual bool equals(const TableFeatureProp & other); + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class TablePropertiesList { +private: + uint16_t length_; + std::list property_list_; +public: + TablePropertiesList() + : length_(0) { + } + TablePropertiesList(std::list property_list); + TablePropertiesList(const TablePropertiesList &other); + TablePropertiesList& operator=(TablePropertiesList other); + ~TablePropertiesList(); + bool operator==(const TablePropertiesList &other) const; + bool operator!=(const TablePropertiesList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + friend void swap(TablePropertiesList& first, TablePropertiesList& second); + uint16_t length() { + return this->length_; + } + std::list property_list() { + return this->property_list_; + } + void property_list(std::list property_list); + void length(uint16_t length) { + this->length_ = length; + } + void add_property(TableFeatureProp* prop); +}; + +class TableFeatures { +private: + uint16_t length_; + uint8_t table_id_; + std::string name_; + uint64_t metadata_match_; + uint64_t metadata_write_; + uint32_t config_; + uint32_t max_entries_; + TablePropertiesList properties_; +public: + TableFeatures() + : length_(sizeof(struct of13::ofp_table_features)) { + } + TableFeatures(uint8_t table_id, std::string name, uint64_t metadata_match, + uint64_t metadata_write, uint32_t config, uint32_t max_entries); + ~TableFeatures() { + } + bool operator==(const TableFeatures &other) const; + bool operator!=(const TableFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length(); + uint8_t table_id() { + return this->table_id_; + } + std::string name() { + return this->name_; + } + uint64_t metadata_match() { + return this->metadata_match_; + } + uint64_t metadata_write() { + return this->metadata_write_; + } + uint32_t config() { + return this->config_; + } + uint32_t max_entries() { + return this->max_entries_; + } + TablePropertiesList properties() { + return this->properties_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void name(std::string name) { + this->name_ = name; + } + void metadata_match(uint64_t metadata_match) { + this->metadata_match_ = metadata_match; + } + void properties(TablePropertiesList properties); + void add_table_prop(TableFeatureProp* prop); + static TableFeatureProp* make_table_feature_prop(uint16_t type); +}; + +} //End of namespace of13 +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/of13/of13instruction.hh b/include/libfluid-msg/of13/of13instruction.hh new file mode 100644 index 00000000..a7dfdcdb --- /dev/null +++ b/include/libfluid-msg/of13/of13instruction.hh @@ -0,0 +1,303 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OPENFLOW_INSTRUCTION_H +#define OPENFLOW_INSTRUCTION_H + +#include "of13action.hh" +#include "openflow-13.h" +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class Instruction { +protected: + uint16_t type_; + uint16_t length_; +public: + Instruction(); + Instruction(uint16_t type, uint16_t length); + virtual ~Instruction() { + } + virtual bool equals(const Instruction & other); + virtual bool operator==(const Instruction &other) const; + virtual bool operator!=(const Instruction &other) const; + virtual uint16_t set_order() const { + return 0; + } + virtual Instruction* clone() { + return new Instruction(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static Instruction* make_instruction(uint16_t type); +}; + +struct comp_inst_set_order { + bool operator()(Instruction* lhs, Instruction* rhs) const { + return lhs->set_order() < rhs->set_order(); + } +}; + +class InstructionSet { +private: + uint16_t length_; + std::set instruction_set_; +public: + InstructionSet() + : length_(0) { + } + InstructionSet(std::set instruction_set); + InstructionSet(const InstructionSet &other); + InstructionSet& operator=(InstructionSet other); + ~InstructionSet(); + bool operator==(const InstructionSet &other) const; + bool operator!=(const InstructionSet &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + friend void swap(InstructionSet& first, InstructionSet& second); + uint16_t length() { + return this->length_; + } + std::set instruction_set(){ + return this->instruction_set_; + } + void add_instruction(Instruction &inst); + void add_instruction(Instruction *inst); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class GoToTable: public Instruction { +private: + uint8_t table_id_; + const uint16_t set_order_; +public: + GoToTable() + : Instruction(of13::OFPIT_GOTO_TABLE, + sizeof(struct of13::ofp_instruction_goto_table)), + set_order_(60) { + } + GoToTable(uint8_t table_id); + ~GoToTable() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual GoToTable* clone() { + return new GoToTable(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint8_t table_id() { + return this->table_id_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } +}; + +class WriteMetadata: public Instruction { +private: + uint64_t metadata_; + uint64_t metadata_mask_; + const uint16_t set_order_; +public: + WriteMetadata() + : Instruction(of13::OFPIT_WRITE_METADATA, + sizeof(struct of13::ofp_instruction_write_metadata)), + set_order_(50) { + } + WriteMetadata(uint64_t metadata, uint64_t metadata_mask); + ~WriteMetadata() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual WriteMetadata* clone() { + return new WriteMetadata(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t metadata() { + return this->metadata_; + } + uint64_t metadata_mask() { + return this->metadata_mask_; + } + void metadata(uint64_t metadata) { + this->metadata_ = metadata; + } + void metadata_mask(uint64_t metadata_mask) { + this->metadata_mask_ = metadata_mask; + } +}; + +class WriteActions: public Instruction { +private: + ActionSet actions_; + const uint16_t set_order_; +public: + WriteActions() + : Instruction(of13::OFPIT_WRITE_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(40) { + } + WriteActions(ActionSet actions); + ~WriteActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + size_t pack(uint8_t* buffer); + virtual WriteActions* clone() { + return new WriteActions(*this); + } + of_error unpack(uint8_t* buffer); + ActionSet actions() { + return this->actions_; + } + void actions(ActionSet actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class ApplyActions: public Instruction { +private: + ActionList actions_; + const uint16_t set_order_; +public: + ApplyActions() + : Instruction(of13::OFPIT_APPLY_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(20) { + } + ApplyActions(ActionList actions); + ~ApplyActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual ApplyActions* clone() { + return new ApplyActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + ActionList actions() { + return this->actions_; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action* action); +}; + +class ClearActions: public Instruction { +private: + const uint16_t set_order_; +public: + ClearActions() + : Instruction(of13::OFPIT_CLEAR_ACTIONS, + sizeof(struct of13::ofp_instruction)), + set_order_(30) { + } + ~ClearActions() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual ClearActions* clone() { + return new ClearActions(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class Meter: public Instruction { +private: + uint32_t meter_id_; + const uint16_t set_order_; +public: + Meter() + : Instruction(of13::OFPIT_METER, + sizeof(struct of13::ofp_instruction_meter)), + set_order_(10) { + } + Meter(uint32_t meter_id); + ~Meter() { + } + uint16_t set_order() const { + return this->set_order_; + } + virtual bool equals(const Instruction & other); + virtual Meter* clone() { + return new Meter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +class InstructionExperimenter: public Instruction { +protected: + uint32_t experimenter_; +public: + InstructionExperimenter() { + } + InstructionExperimenter(uint32_t experimenter); + ~InstructionExperimenter() { + } + virtual bool equals(const Instruction & other); + virtual InstructionExperimenter* clone() { + return new InstructionExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +} + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/of13match.hh b/include/libfluid-msg/of13/of13match.hh new file mode 100644 index 00000000..f02cde8e --- /dev/null +++ b/include/libfluid-msg/of13/of13match.hh @@ -0,0 +1,1233 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OPENFLOW_MATCH_H +#define OPENFLOW_MATCH_H 1 + +#include +#include +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" +#include "openflow-13.h" +#include +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class MatchHeader { +protected: + uint16_t type_; + uint16_t length_; +public: + MatchHeader(); + MatchHeader(uint16_t type, uint16_t length); + virtual ~MatchHeader() { + } + bool operator==(const MatchHeader &other) const; + bool operator!=(const MatchHeader &other) const; + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } +}; + +struct oxm_req { + uint16_t eth_type_req[2]; + uint8_t ip_proto_req; + uint8_t icmp_req; +}; + +class OXMTLV { +protected: + uint16_t class__; + uint8_t field_; + bool has_mask_; + uint8_t length_; + struct oxm_req reqs; + void create_oxm_req(uint16_t eth_type1, uint16_t eth_type2, + uint8_t ip_proto, uint8_t icmp); +public: + OXMTLV(); + OXMTLV(uint16_t class_, uint8_t field, bool has_mask, uint8_t length); + virtual ~OXMTLV() { + } + virtual bool equals(const OXMTLV & other); + virtual bool operator==(const OXMTLV &other) const; + virtual bool operator!=(const OXMTLV &other) const; + virtual OXMTLV& operator=(const OXMTLV& field); + virtual OXMTLV* clone() const { + return new OXMTLV(*this); + } + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + uint16_t class_() const { + return this->class__; + } + uint8_t field() const { + return this->field_; + } + bool has_mask() const { + return this->has_mask_; + } + uint8_t length() { + return this->length_; + } + struct oxm_req oxm_reqs() const { + return this->reqs; + } + + void class_(uint16_t class_) { + this->class__ = class_; + } + void field(uint8_t field) { + this->field_ = field; + } + void has_mask(bool has_mask) { + this->has_mask_ = has_mask; + } + void length(uint8_t length) { + this->length_ = length; + } + static uint32_t make_header(uint16_t class_, uint8_t field, bool has_mask, + uint8_t length); + static uint16_t oxm_class(uint32_t header); + static uint8_t oxm_field(uint32_t header); + static bool oxm_has_mask(uint32_t header); + static uint8_t oxm_length(uint32_t header); +}; + +class InPort: public OXMTLV { +private: + uint32_t value_; +public: + InPort(); + InPort(uint32_t value); + ~InPort() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual InPort* clone() const { + return new InPort(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class InPhyPort: public OXMTLV { +private: + uint32_t value_; +public: + InPhyPort(); + InPhyPort(uint32_t value); + ~InPhyPort() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual InPhyPort* clone() const { + return new InPhyPort(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class Metadata: public OXMTLV { +private: + uint64_t value_; + uint64_t mask_; +public: + Metadata(); + Metadata(uint64_t value); + Metadata(uint64_t value, uint64_t mask); + ~Metadata() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual Metadata* clone() const { + return new Metadata(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint64_t value() const { + return this->value_; + } + uint64_t mask() const { + return this->mask_; + } + void value(uint64_t value) { + this->value_ = value; + } + void mask(uint64_t mask) { + this->mask_ = mask; + } +}; + +class EthDst: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + EthDst(); + EthDst(EthAddress value); + EthDst(EthAddress value, EthAddress mask); + ~EthDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthDst* clone() const { + return new EthDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + void mask(EthAddress mask) { + this->mask_ = mask; + } +}; + +class EthSrc: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + EthSrc(); + EthSrc(EthAddress value); + EthSrc(EthAddress value, EthAddress mask); + ~EthSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthSrc* clone() const { + return new EthSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + void mask(EthAddress mask) { + this->mask_ = mask; + } +}; + +class EthType: public OXMTLV { +private: + uint16_t value_; +public: + EthType(); + EthType(uint16_t value); + ~EthType() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual EthType* clone() const { + return new EthType(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class VLANVid: public OXMTLV { +private: + uint16_t value_; + uint16_t mask_; +public: + VLANVid(); + VLANVid(uint16_t value); + VLANVid(uint16_t value, uint16_t mask); + ~VLANVid() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual VLANVid* clone() const { + return new VLANVid(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + uint16_t mask() const { + return this->mask_; + } + void value(uint16_t value) { + this->value_ = value; + } + void mask(uint16_t mask) { + this->mask_ = mask; + } +}; + +class VLANPcp: public OXMTLV { +private: + uint8_t value_; +public: + VLANPcp(); + VLANPcp(uint8_t value); + ~VLANPcp() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual VLANPcp* clone() const { + return new VLANPcp(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPDSCP: public OXMTLV { +private: + uint8_t value_; +public: + IPDSCP(); + IPDSCP(uint8_t value); + ~IPDSCP() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPDSCP* clone() const { + return new IPDSCP(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPECN: public OXMTLV { +private: + uint8_t value_; +public: + IPECN(); + IPECN(uint8_t value); + ~IPECN() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPECN* clone() const { + return new IPECN(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPProto: public OXMTLV { +private: + uint8_t value_; +public: + IPProto(); + IPProto(uint8_t value); + ~IPProto() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPProto* clone() const { + return new IPProto(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPv4Src: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv4Src(); + IPv4Src(IPAddress value); + IPv4Src(IPAddress value, IPAddress mask); + ~IPv4Src() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv4Src* clone() const { + return new IPv4Src(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class IPv4Dst: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv4Dst(); + IPv4Dst(IPAddress value); + IPv4Dst(IPAddress value, IPAddress mask); + ~IPv4Dst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv4Dst* clone() const { + return new IPv4Dst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class TCPSrc: public OXMTLV { +private: + uint16_t value_; +public: + TCPSrc(); + TCPSrc(uint16_t value); + ~TCPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TCPSrc* clone() const { + return new TCPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } + +}; + +class TCPDst: public OXMTLV { +private: + uint16_t value_; +public: + TCPDst(); + TCPDst(uint16_t value); + ~TCPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TCPDst* clone() const { + return new TCPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class UDPSrc: public OXMTLV { +private: + uint16_t value_; +public: + UDPSrc(); + UDPSrc(uint16_t value); + ~UDPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual UDPSrc* clone() const { + return new UDPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class UDPDst: public OXMTLV { +private: + uint16_t value_; +public: + UDPDst(); + UDPDst(uint16_t value); + ~UDPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual UDPDst* clone() const { + return new UDPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class SCTPSrc: public OXMTLV { +private: + uint16_t value_; +public: + SCTPSrc(); + SCTPSrc(uint16_t value); + ~SCTPSrc() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual SCTPSrc* clone() const { + return new SCTPSrc(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } + +}; + +class SCTPDst: public OXMTLV { +private: + uint16_t value_; +public: + SCTPDst(); + SCTPDst(uint16_t value); + ~SCTPDst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual SCTPDst* clone() const { + return new SCTPDst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class ICMPv4Code: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv4Code(); + ICMPv4Code(uint8_t value); + ~ICMPv4Code() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv4Code* clone() const { + return new ICMPv4Code(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ICMPv4Type: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv4Type(); + ICMPv4Type(uint8_t value); + ~ICMPv4Type() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv4Type* clone() const { + return new ICMPv4Type(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ARPOp: public OXMTLV { +private: + uint16_t value_; +public: + ARPOp(); + ARPOp(uint16_t value); + ~ARPOp() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPOp* clone() const { + return new ARPOp(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + void value(uint16_t value) { + this->value_ = value; + } +}; + +class ARPSPA: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + ARPSPA(); + ARPSPA(IPAddress value); + ARPSPA(IPAddress value, IPAddress mask); + ~ARPSPA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPSPA* clone() const { + return new ARPSPA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } + +}; + +class ARPTPA: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + ARPTPA(); + ARPTPA(IPAddress value); + ARPTPA(IPAddress value, IPAddress mask); + ~ARPTPA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPTPA* clone() const { + return new ARPTPA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class ARPSHA: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + ARPSHA(); + ARPSHA(EthAddress value); + ARPSHA(EthAddress value, EthAddress mask); + ~ARPSHA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPSHA* clone() const { + return new ARPSHA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class ARPTHA: public OXMTLV { +private: + EthAddress value_; + EthAddress mask_; +public: + ARPTHA(); + ARPTHA(EthAddress value); + ARPTHA(EthAddress value, EthAddress mask); + ~ARPTHA() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ARPTHA* clone() const { + return new ARPTHA(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + EthAddress mask() const { + return this->mask_; + } + void value(EthAddress value) { + this->value_ = value; + } + //void value(std::string value); +}; + +class IPv6Src: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv6Src(); + IPv6Src(IPAddress value); + IPv6Src(IPAddress value, IPAddress mask); + ~IPv6Src() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Src* clone() const { + return new IPv6Src(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class IPv6Dst: public OXMTLV { +private: + IPAddress value_; + IPAddress mask_; +public: + IPv6Dst(); + IPv6Dst(IPAddress value); + IPv6Dst(IPAddress value, IPAddress mask); + ~IPv6Dst() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Dst* clone() const { + return new IPv6Dst(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + IPAddress mask() const { + return this->mask_; + } + void value(IPAddress value) { + this->value_ = value; + } + void mask(IPAddress mask) { + this->mask_ = mask; + } +}; + +class IPV6Flabel: public OXMTLV { +private: + uint32_t value_; + uint32_t mask_; +public: + IPV6Flabel(); + IPV6Flabel(uint32_t value); + IPV6Flabel(uint32_t value, uint32_t mask); + ~IPV6Flabel() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPV6Flabel* clone() const { + return new IPV6Flabel(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + uint32_t mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class ICMPv6Type: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv6Type(); + ICMPv6Type(uint8_t value); + ~ICMPv6Type() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv6Type* clone() const { + return new ICMPv6Type(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class ICMPv6Code: public OXMTLV { +private: + uint8_t value_; +public: + ICMPv6Code(); + ICMPv6Code(uint8_t value); + ~ICMPv6Code() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual ICMPv6Code* clone() const { + return new ICMPv6Code(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class IPv6NDTarget: public OXMTLV { +private: + IPAddress value_; +public: + IPv6NDTarget(); + IPv6NDTarget(IPAddress value); + ~IPv6NDTarget() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDTarget* clone() const { + return new IPv6NDTarget(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + IPAddress value() const { + return this->value_; + } + void value(IPAddress value) { + this->value_ = value; + } +}; + +class IPv6NDSLL: public OXMTLV { +private: + EthAddress value_; +public: + IPv6NDSLL(); + IPv6NDSLL(EthAddress value); + ~IPv6NDSLL() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDSLL* clone() const { + return new IPv6NDSLL(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class IPv6NDTLL: public OXMTLV { +private: + EthAddress value_; +public: + IPv6NDTLL(); + IPv6NDTLL(EthAddress value); + ~IPv6NDTLL() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6NDTLL* clone() const { + return new IPv6NDTLL(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + EthAddress value() const { + return this->value_; + } + void value(EthAddress value) { + this->value_ = value; + } +}; + +class MPLSLabel: public OXMTLV { +private: + uint32_t value_; +public: + MPLSLabel(); + MPLSLabel(uint32_t value); + ~MPLSLabel() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSLabel* clone() const { + return new MPLSLabel(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + void value(uint32_t value) { + this->value_ = value; + } +}; + +class MPLSTC: public OXMTLV { +private: + uint8_t value_; +public: + MPLSTC(); + MPLSTC(uint8_t value); + ~MPLSTC() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSTC* clone() const { + return new MPLSTC(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class MPLSBOS: public OXMTLV { +private: + uint8_t value_; +public: + MPLSBOS(); + MPLSBOS(uint8_t value); + ~MPLSBOS() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual MPLSBOS* clone() const { + return new MPLSBOS(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint8_t value() const { + return this->value_; + } + void value(uint8_t value) { + this->value_ = value; + } +}; + +class PBBIsid: public OXMTLV { +private: + uint32_t value_; + uint32_t mask_; +public: + PBBIsid(); + PBBIsid(uint32_t value); + PBBIsid(uint32_t value, uint32_t mask); + ~PBBIsid() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual PBBIsid* clone() const { + return new PBBIsid(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint32_t value() const { + return this->value_; + } + uint32_t mask() const { + return this->mask_; + } + void value(uint32_t value) { + this->value_ = value; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } +}; + +class TUNNELId: public OXMTLV { +private: + uint64_t value_; + uint64_t mask_; +public: + TUNNELId(); + TUNNELId(uint64_t value); + TUNNELId(uint64_t value, uint64_t mask); + ~TUNNELId() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual TUNNELId* clone() const { + return new TUNNELId(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint64_t value() const { + return this->value_; + } + void value(uint64_t value) { + this->value_ = value; + } +}; + +class IPv6Exthdr: public OXMTLV { +private: + uint16_t value_; + uint16_t mask_; +public: + IPv6Exthdr(); + IPv6Exthdr(uint16_t value); + IPv6Exthdr(uint16_t value, uint16_t mask); + ~IPv6Exthdr() { + } + virtual bool equals(const OXMTLV & other); + OXMTLV& operator=(const OXMTLV& field); + virtual IPv6Exthdr* clone() const { + return new IPv6Exthdr(*this); + } + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + uint16_t value() const { + return this->value_; + } + uint16_t mask() const { + return this->mask_; + } + void value(uint16_t value) { + this->value_ = value; + } + void mask(uint16_t mask) { + this->mask_ = mask; + } +}; + +class Match: public MatchHeader { +private: + /*Current tlvs present by field*/ + std::vector curr_tlvs_; + /*Vector of OXM TLVs*/ + OXMTLV* oxm_tlvs_[OXM_NUM]; +public: + Match(); + Match(const Match &match); + Match& operator=(Match other); + ~Match(); + bool operator==(const Match &other) const; + bool operator!=(const Match &other) const; + static void swap(Match& first, Match& second); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + OXMTLV *oxm_field(uint8_t field); + bool check_pre_req(OXMTLV *tlv); + bool check_dup(OXMTLV *tlv); + void add_oxm_field(OXMTLV &tlv); + void add_oxm_field(OXMTLV* tlv); + uint16_t oxm_fields_len(); + static OXMTLV * make_oxm_tlv(uint8_t field); + InPort* in_port(); + InPhyPort* in_phy_port(); + Metadata* metadata(); + EthSrc* eth_src(); + EthDst* eth_dst(); + EthType* eth_type(); + VLANVid* vlan_vid(); + VLANPcp* vlan_pcp(); + IPDSCP* ip_dscp(); + IPECN* ip_ecn(); + IPProto* ip_proto(); + IPv4Src* ipv4_src(); + IPv4Dst* ipv4_dst(); + TCPSrc* tcp_src(); + TCPDst* tcp_dst(); + UDPSrc* udp_src(); + UDPDst* udp_dst(); + SCTPSrc* sctp_src(); + SCTPDst* sctp_dst(); + ICMPv4Type* icmpv4_type(); + ICMPv4Code* icmpv4_code(); + ARPOp* arp_op(); + ARPSPA* arp_spa(); + ARPTPA* arp_tpa(); + ARPSHA* arp_sha(); + ARPTHA* arp_tha(); + IPv6Src* ipv6_src(); + IPv6Dst* ipv6_dst(); + IPV6Flabel* ipv6_flabel(); + ICMPv6Type* icmpv6_type(); + ICMPv6Code* icmpv6_code(); + IPv6NDTarget* ipv6_nd_target(); + IPv6NDSLL* ipv6_nd_sll(); + IPv6NDTLL* ipv6_nd_tll(); + MPLSLabel* mpls_label(); + MPLSTC* mpls_tc(); + MPLSBOS* mpls_bos(); + PBBIsid* pbb_isid(); + TUNNELId* tunnel_id(); + IPv6Exthdr* ipv6_exthdr(); +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/of13/of13meter.hh b/include/libfluid-msg/of13/of13meter.hh new file mode 100644 index 00000000..c1ba6d8a --- /dev/null +++ b/include/libfluid-msg/of13/of13meter.hh @@ -0,0 +1,330 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OPENFLOW_METER_H +#define OPENFLOW_METER_H + +#include +#include "openflow-13.h" +#include +#include + +namespace fluid_msg { + +namespace of13 { + +class MeterBand { +protected: + uint16_t type_; + uint16_t len_; + uint32_t rate_; + uint32_t burst_size_; +public: + MeterBand(); + MeterBand(uint16_t type, uint32_t rate, uint32_t burst_size); + virtual ~MeterBand() { + } + virtual bool equals(const MeterBand & other); + virtual MeterBand* clone() { + return new MeterBand(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t type() { + return this->type_; + } + uint16_t len() { + return this->len_; + } + uint32_t rate() { + return this->rate_; + } + uint32_t burst_size() { + return this->burst_size_; + } + void type(uint16_t type) { + this->type_ = type; + } + void rate(uint32_t rate) { + this->rate_ = rate; + } + void burst_size(uint32_t burst_size) { + this->burst_size_ = burst_size; + } + static bool delete_all(MeterBand * band) { + delete band; + return true; + } + static MeterBand * make_meter_band(uint16_t type); +}; + +class MeterBandList { +private: + uint16_t length_; + std::list band_list_; +public: + MeterBandList() + : length_(0) { + } + MeterBandList(std::list band_list); + MeterBandList(const MeterBandList &other); + MeterBandList& operator=(MeterBandList other); + ~MeterBandList(); + bool operator==(const MeterBandList &other) const; + bool operator!=(const MeterBandList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::vector meter_bands() const { + return std::vector(band_list_.begin(), band_list_.end()); + } + friend void swap(MeterBandList& first, MeterBandList& second); + uint16_t length() { + return this->length_; + } + void add_band(MeterBand *band); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class MeterBandDrop: public MeterBand { +public: + MeterBandDrop(); + MeterBandDrop(uint32_t rate, uint32_t burst_size); + ~MeterBandDrop() { + } + virtual MeterBandDrop* clone() { + return new MeterBandDrop(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); +}; + +class MeterBandDSCPRemark: public MeterBand { +private: + uint8_t prec_level_; +public: + MeterBandDSCPRemark(); + MeterBandDSCPRemark(uint32_t rate, uint32_t burst_size, uint8_t prec_level); + ~MeterBandDSCPRemark() { + } + virtual bool equals(const MeterBand & other); + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + virtual MeterBandDSCPRemark* clone() { + return new MeterBandDSCPRemark(*this); + } + uint8_t prec_level() { + return this->prec_level_; + } + void prec_level(uint8_t prec_level) { + this->prec_level_ = prec_level; + } +}; + +class MeterBandExperimenter: public MeterBand { +protected: + uint32_t experimenter_; +public: + MeterBandExperimenter(); + MeterBandExperimenter(uint32_t rate, uint32_t burst_size, + uint32_t experimenter); + ~MeterBandExperimenter() { + } + virtual bool equals(const MeterBand & other); + virtual MeterBandExperimenter* clone() { + return new MeterBandExperimenter(*this); + } + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t experimenter() { + return this->experimenter_; + } + void experimenter(uint32_t experimenter) { + this->experimenter_ = experimenter; + } +}; + +class MeterConfig { +private: + uint16_t length_; + uint16_t flags_; + uint32_t meter_id_; + MeterBandList bands_; +public: + MeterConfig(); + MeterConfig(uint16_t flags, uint32_t meter_id); + MeterConfig(uint16_t flags, uint32_t meter_id, MeterBandList bands); + ~MeterConfig() { + } + bool operator==(const MeterConfig &other) const; + bool operator!=(const MeterConfig &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint16_t length() { + return this->length_; + } + uint16_t flags() { + return this->flags_; + } + uint32_t meter_id() { + return this->meter_id_; + } + MeterBandList bands() { + return this->bands_; + } + void bands(MeterBandList bands); + void add_band(MeterBand* band); +}; + +class MeterFeatures { +private: + uint32_t max_meter_; + uint32_t band_types_; + uint32_t capabilities_; + uint8_t max_bands_; + uint8_t max_color_; +public: + MeterFeatures(); + MeterFeatures(uint32_t max_meter, uint32_t band_types, + uint32_t capabilities, uint8_t max_bands, uint8_t max_color); + ~MeterFeatures() { + } + bool operator==(const MeterFeatures &other) const; + bool operator!=(const MeterFeatures &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t max_meter() { + return this->max_meter_; + } + uint32_t band_types() { + return this->band_types_; + } + uint32_t capabilities() { + return this->capabilities_; + } + uint8_t max_bands() { + return this->max_bands_; + } + uint8_t max_color() { + return this->max_color_; + } + void max_meter(uint32_t max_meter) { + this->max_meter_ = max_meter; + } + void banc_types(uint32_t band_types) { + this->band_types_ = band_types; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } + void max_bands(uint8_t max_bands) { + this->max_bands_ = max_bands; + } + void max_color(uint8_t max_color) { + this->max_color_ = max_color; + } +}; + +class BandStats { +private: + uint64_t packet_band_count_; + uint64_t byte_band_count_; +public: + BandStats(); + BandStats(uint64_t packet_band_count, uint64_t byte_band_count); + ~BandStats() { + } + bool operator==(const BandStats &other) const; + bool operator!=(const BandStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t packet_band_count() { + return this->packet_band_count_; + } + uint64_t byte_band_count() { + return this->byte_band_count_; + } +}; + +class MeterStats { +private: + uint32_t meter_id_; + uint16_t len_; + uint32_t flow_count_; + uint64_t packet_in_count_; + uint64_t byte_in_count_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + std::vector band_stats_; + +public: + MeterStats(); + MeterStats(uint32_t meter_id, uint32_t flow_count, uint64_t packet_in_count, + uint64_t byte_in_count, uint32_t duration_sec, uint32_t duration_nsec); + MeterStats(uint32_t meter_id, uint32_t flow_count, uint64_t packet_in_count, + uint64_t byte_in_count, uint32_t duration_sec, uint32_t duration_nsec, + std::vector band_stats); + ~MeterStats() { + } + bool operator==(const MeterStats &other) const; + bool operator!=(const MeterStats &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint32_t meter_id() { + return this->meter_id_; + } + uint16_t len() { + return this->len_; + } + uint64_t packet_in_count() { + return this->packet_in_count_; + } + uint64_t byte_in_count() { + return this->byte_in_count_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + std::vector band_stats() { + return this->band_stats_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } + void packet_in_count(uint64_t packet_in_count) { + this->packet_in_count_ = packet_in_count; + } + void byte_in_count(uint64_t byte_in_count) { + this->byte_in_count_ = byte_in_count; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint64_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void band_stats(std::vector band_stats); + + void add_band_stats(BandStats stats); +}; + +} //End of namespace of13 + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/of13/openflow-13.h b/include/libfluid-msg/of13/openflow-13.h new file mode 100644 index 00000000..177b534e --- /dev/null +++ b/include/libfluid-msg/of13/openflow-13.h @@ -0,0 +1,1754 @@ +/* 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_OPENFLOW13_H +#define OPENFLOW_OPENFLOW13_H 1 + +#include "../ofcommon/openflow-common.hh" + +namespace fluid_msg { + +namespace of13 { + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +const uint8_t OFP_VERSION = 0x04; +/* Number of tables in the pipeline */ +#define PIPELINE_TABLES 64 + +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 */ + /* 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 */ + /* Asynchronous messages. */ + 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 */ + /* Barrier messages. */ + 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 */ + /* 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 */ + /* Meters and rate limiters configuration messages. */ + OFPT_METER_MOD = 29, /* Controller/switch message */ +}; + +/* Common header for all Hello Elements */ +struct ofp_hello_elem_header { + uint16_t type; /* One of OFPHET_*. */ + uint16_t length; /* Length in bytes of this element. */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_header) == 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_fluid_header header; + /* Hello element list */ + struct ofp_hello_elem_header elements[0]; +}; +OFP_ASSERT(sizeof(struct ofp_hello) == 8); + +/* Hello elements types. + */ +enum ofp_hello_elem_type { + OFPHET_VERSIONBITMAP = 1, +}; + +/* Version bitmap Hello Element */ +struct ofp_hello_elem_versionbitmap { + uint16_t type; + /* OFPHET_VERSIONBITMAP. */ + uint16_t length; /* Length in bytes of this element. */ + /* 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); + +/******** Common Structures **********************/ + +/* 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 */ +}; +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. */ +}; + +/* 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. */ +}; + +/* Port numbering. Ports are numbered starting from 1. */ +enum ofp_port_no { + /* Maximum number of physical and logical switch ports. */ + OFPP_FLUID_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_FLUID_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_FLUID_CONTROLLER = 0xfffffffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ + OFPP_FLUID_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). */ +}; + +/* 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_PAUSE_ASYM = 1 << 15 /* Asymmetric pause. */ +}; + +/* 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); + +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_FLUID_ALL 0xffffffff + +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff + +enum ofp_queue_properties { + OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ + OFPQT_MAX_RATE = 2, /* Maximum datarate. */ + OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ +}; + +/* 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_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 */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); + +/* 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); + +const uint8_t OFP_OXM_HEADER_LEN = 4; +const uint8_t OFP_OXM_IN_PORT_LEN = 4; +const uint8_t OFP_OXM_IN_PHY_PORT_LEN = 4; +const uint8_t OFP_OXM_METADATA_LEN = 8; +const uint8_t OFP_OXM_ETH_TYPE_LEN = 2; +const uint8_t OFP_OXM_VLAN_VID_LEN = 2; +const uint8_t OFP_OXM_VLAN_PCP_LEN = 1; +const uint8_t OFP_OXM_IP_DSCP_LEN = 1; +const uint8_t OFP_OXM_IP_ECN_LEN = 1; +const uint8_t OFP_OXM_IP_PROTO_LEN = 1; +const uint8_t OFP_OXM_IPV4_LEN = 4; +const uint8_t OFP_OXM_TP_LEN = 2; +const uint8_t OFP_OXM_ARP_OP_LEN = 2; +const uint8_t OFP_OXM_ICMP_TYPE_LEN = 1; +const uint8_t OFP_OXM_ICMP_CODE_LEN = 1; +const uint8_t OFP_OXM_IPV6_LEN = 16; +const uint8_t OFP_OXM_IPV6_FLABEL_LEN = 4; +const uint8_t OFP_OXM_MPLS_TC_LEN = 1; +const uint8_t OFP_OXM_MPLS_LABEL_LEN = 4; +const uint8_t OFP_OXM_MPLS_BOS_LEN = 1; +const uint8_t OFP_OXM_IPV6_PBB_ISID_LEN = 4; +const uint8_t OFP_OXM_TUNNEL_ID_LEN = 8; +const uint8_t OFP_OXM_IPV6_EXTHDR_LEN = 2; + +/* 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 */ +}; +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 */ +}; + +/* 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. + */ +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 */ +}; + +#define OXM_NUM 40 + +/* 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_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 */ +}; + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * 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. */ +}; + +/* 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. */ +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. */ +}; +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 */ +}; + +enum ofp_action_type { + 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_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_EXPERIMENTER = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out ’port’. + * When the ’port’ is the OFPP_FLUID_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_output) == 16); + +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. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); + +/* 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]; +}; +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]; +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_action_pop_mpls) == 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 */ +}; +OFP_ASSERT(sizeof(struct ofp_action_set_field) == 8); + +/* Action header for OFPAT_EXPERIMENTER. + * 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_experimenter_header) == 8); + +/* 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); + +/* 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); + +/* Instruction structure for experimental instructions */ +struct ofp_instruction_experimenter { + uint16_t type; /* OFPIT_EXPERIMENTER */ + uint16_t len; /* Length of this struct in bytes */ + /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint32_t experimenter; + /* Experimenter-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_instruction_experimenter) == 8); + +/*************Controller-to-Switch Messages******************/ + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_fluid_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; +}; +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. */ +}; + +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 */ +}; + +/* 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. */ +}; + +/* Configure/Modify behavior of a flow table */ +struct ofp_table_mod { + struct ofp_fluid_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); + +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 +}; + +#define OFP_FLUID_DEFAULT_PRIORITY 0x8000 +#define OFP_FLUID_FLOW_PERMANENT 0 + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_fluid_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_FLUID_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); + +enum ofp_flow_mod_command { + 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_STRICT = 4, /* Delete entry strictly matching wildcards and + priority. */ +}; + +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. */ +}; + +/* Group numbering. Groups can use any number up to OFPG_MAX. */ +enum ofp_group { + /* Last usable group number. */ + OFPG_MAX = 0xffffff00, + + /* 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).*/ +}; + +/* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_bucket) == 16); + +/* Group setup and teardown (controller -> datapath). */ +struct ofp_group_mod { + struct ofp_fluid_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. */ +enum ofp_group_type { + OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ + OFPGT_SELECT = 1, /* Select group. */ + OFPGT_INDIRECT = 2, /* Indirect group. */ + OFPGT_FF = 3, /* Fast failover group. */ +}; + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_fluid_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); + +/* 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); + +/* Meter configuration. OFPT_METER_MOD. */ +struct ofp_meter_mod { + struct ofp_fluid_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); + +/* 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. */ +}; + +/* 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 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 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]; +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_dscp_remark) == 16); + +/* OFPMBT_EXPERIMENTER band - Write actions in action set */ +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. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_experimenter) == 16); + +struct ofp_multipart_request { + struct ofp_fluid_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_ASSERT(sizeof(struct ofp_multipart_request) == 16); + +enum ofp_multipart_request_flags { + OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ +}; + +enum ofp_multipart_reply_flags { + OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_multipart_reply { + struct ofp_fluid_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. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); + +enum ofp_multipart_types { + /* Description of this OpenFlow switch. + * 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. */ + OFPMP_FLOW = 1, + /* Aggregate flow statistics. + * 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. */ + 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. */ + 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 */ + 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. */ + OFPMP_GROUP = 6, + /* Group description statistics. + * The request body is empty. + * The reply body is an array of struct ofp_group_desc_stats. */ + OFPMP_GROUP_DESC = 7, + /* Group features. + * The request body is empty. + * The reply body is struct ofp_group_features_stats. */ + 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. */ + OFPMP_METER_CONFIG = 10, + /* 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. */ + OFPMP_TABLE_FEATURES = 12, + /* Port description. + * 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. */ + OFPMP_EXPERIMENTER = 0xffff +}; + +/* 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_FLUID_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. */ + uint16_t 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. */ + //struct ofp_instruction instructions[0]; /* Instruction set. */ +}; +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_FLUID_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. */ +}; +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_FLUID_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. + */ +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. */ +}; + +/* 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. */ + /* 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 */ +}; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_instructions) == 4); + +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. */ + /* 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]; +}; +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. */ + /* 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 */ +}; +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. */ + /* 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 */ +}; +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_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_FLUID_ANY). */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* 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. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 112); + +struct ofp_queue_stats_request { + uint32_t port_no; /* All ports if OFPP_FLUID_ANY. */ + uint32_t queue_id; /* All queues if OFPQ_FLUID_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_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 + duration_sec. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); + +/* 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. */ +}; +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. */ +}; +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 + duration_sec. */ + struct ofp_bucket_counter bucket_stats[0]; + +}; +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]; +}; +OFP_ASSERT(sizeof(struct ofp_group_desc_stats) == 8); + +/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ +struct ofp_group_features { + 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) == 40); + +/* 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 */ +}; + +/* 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. */ +}; +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. */ +}; +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. */ + struct ofp_meter_band_stats band_stats[0]; /* The band_stats length is + 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. */ + struct ofp_meter_band_header bands[0]; /* The bands length is + 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]; +}; +OFP_ASSERT(sizeof(struct ofp_meter_features) == 16); + +/* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */ +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_experimenter_multipart_header) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_fluid_header header; + uint32_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_FLUID_MAX), + or OFPP_FLUID_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_fluid_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_fluid_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_FLUID_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.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 24); + +#define OFP_NO_BUFFER 0xffffffff + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_fluid_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 */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); + +/* 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 */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_fluid_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); + +/* 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. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_fluid_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_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. */ +}; + +/* 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_fluid_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_fluid_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_fluid_header.version not supported. */ + OFPBRC_BAD_TYPE = 1, /* ofp_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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_fluid_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. */ +}; + +/* ofp_fluid_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. */ +}; + +/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ +struct ofp_error_experimenter_msg { + struct ofp_fluid_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_error_experimenter_msg) == 16); + +/* Experimenter extension. */ +struct ofp_experimenter_header { + struct ofp_fluid_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); + +} + +} //End of namespace fluid_msg + +#endif /* openflow/openflow.h */ diff --git a/include/libfluid-msg/of13msg.hh b/include/libfluid-msg/of13msg.hh new file mode 100644 index 00000000..d2839d22 --- /dev/null +++ b/include/libfluid-msg/of13msg.hh @@ -0,0 +1,1596 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OF13MSG_H +#define OF13MSG_H 1 + +#include "ofcommon/msg.hh" +#include "of13/of13common.hh" +#include "of13/of13action.hh" +#include "of13/of13meter.hh" + +namespace fluid_msg { + +/** + Base class for OpenFlow 1.3 Role messages. + */ +class RoleCommon: public OFMsg { +private: + uint32_t role_; + uint64_t generation_id_; +public: + RoleCommon(uint8_t version, uint8_t type); + RoleCommon(uint8_t version, uint8_t type, uint32_t xid, uint32_t role, + uint64_t generation_id); + virtual ~RoleCommon() { + } + bool operator==(const RoleCommon &other) const; + bool operator!=(const RoleCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t role() { + return this->role_; + } + uint64_t generation_id() { + return this->generation_id_; + } + void role(uint32_t role) { + this->role_ = role; + } + void generation_id(uint64_t generation_id) { + this->generation_id_ = generation_id; + } +}; + +/** + Base class for OpenFlow 1.3 Async Config messages. + */ +class AsyncConfigCommon: public OFMsg { +protected: + std::vector packet_in_mask_; + std::vector port_status_mask_; + std::vector flow_removed_mask_; +public: + AsyncConfigCommon(uint8_t version, uint8_t type); + AsyncConfigCommon(uint8_t version, uint8_t type, uint32_t xid); + AsyncConfigCommon(uint8_t version, uint8_t type, uint32_t xid, + std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + virtual ~AsyncConfigCommon() { + } + bool operator==(const AsyncConfigCommon &other) const; + bool operator!=(const AsyncConfigCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + /*TODO check for specific message type */ + uint32_t master_equal_packet_in_mask() { + return this->packet_in_mask_[0]; + } + uint32_t master_equal_port_status_mask() { + return this->port_status_mask_[0]; + } + uint32_t master_equal_flow_removed_mask() { + return this->port_status_mask_[0]; + } + uint32_t slave_packet_in_mask() { + return this->packet_in_mask_[1]; + } + uint32_t slave_port_status_mask() { + return this->port_status_mask_[1]; + } + uint32_t slave_flow_removed_mask() { + return this->port_status_mask_[1]; + } + void master_equal_packet_in_mask(uint32_t mask) { + this->packet_in_mask_[0] = mask; + } + void master_equal_port_status_mask(uint32_t mask) { + this->port_status_mask_[0] = mask; + } + void master_equal_flow_removed_mask(uint32_t mask) { + this->port_status_mask_[0] = mask; + } + void slave_packet_in_mask(uint32_t mask) { + this->packet_in_mask_[1] = mask; + } + void slave_port_status_mask(uint32_t mask) { + this->port_status_mask_[1] = mask; + } + void slave_flow_removed_mask(uint32_t mask) { + this->port_status_mask_[1] = mask; + } +}; + +/** + Classes for creating and parsing OpenFlow 1.3 messages. + */ +namespace of13 { + +/** + OpenFlow 1.3 OFPT_HELLO message + */ +class Hello: public OFMsg { +private: + std::list elements_; +public: + Hello(); + Hello(uint32_t xid); + Hello(uint32_t xid, std::list elements); + ~Hello() { + } + bool operator==(const Hello &other) const; + bool operator!=(const Hello &other) const; + uint8_t* pack(); + of_error unpack(uint8_t* buffer); + std::list elements() { + return this->elements_; + } + void elements(std::list elements); + void add_element(HelloElemVersionBitmap element); + uint32_t elements_len(); +}; + +/** + OpenFlow 1.3 OFPT_ERROR message. + */ +class Error: public ErrorCommon { +public: + Error(); + Error(uint32_t xid, uint16_t err_type, uint16_t code); + Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len); + ~Error() { + } +}; + +/** + OpenFlow 1.3 OFPT_ECHO_REQUEST message. + */ +class EchoRequest: public EchoCommon { +public: + EchoRequest(); + EchoRequest(uint32_t xid); + ~EchoRequest() { + } +}; + +/** + OpenFlow 1.3 OFPT_ECHO_REPLY message. + */ +class EchoReply: public EchoCommon { +public: + EchoReply(); + EchoReply(uint32_t xid); + ~EchoReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_EXPERIMENTER message. + Experimenter messages should inherit from this class. + */ +class Experimenter: public OFMsg { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + Experimenter(); + Experimenter(uint32_t xid, uint32_t experimenter, uint32_t exp_type); + virtual ~Experimenter() { + } + bool operator==(const Experimenter &other) const; + bool operator!=(const Experimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPT_FEATURES_REQUEST message. + */ +class FeaturesRequest: public OFMsg { +public: + FeaturesRequest(); + FeaturesRequest(uint32_t xid); + ~FeaturesRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_FEATURES_REPLY message. + */ +class FeaturesReply: public FeaturesReplyCommon { + uint8_t auxiliary_id_; +public: + FeaturesReply(); + FeaturesReply(uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, + uint8_t n_tables, uint8_t auxiliary_id, uint32_t capabilities); + ~FeaturesReply() { + } + bool operator==(const FeaturesReply &other) const; + bool operator!=(const FeaturesReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t auxiliary_id() { + return this->auxiliary_id_; + } + void auxiliary_id(uint8_t auxiliary_id) { + this->auxiliary_id_ = auxiliary_id; + } +}; + +/** + OpenFlow 1.3 OFPT_GET_CONFIG_REQUEST message. + */ +class GetConfigRequest: public OFMsg { +public: + GetConfigRequest(); + GetConfigRequest(uint32_t xid); + ~GetConfigRequest() { + } + ; + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_GET_CONFIG_REPLY message. + */ +class GetConfigReply: public SwitchConfigCommon { +public: + GetConfigReply(); + GetConfigReply(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~GetConfigReply() { + } + ; +}; + +/** + OpenFlow 1.3 OFPT_SET_CONFIG_REPLY message. + */ +class SetConfig: public SwitchConfigCommon { +public: + SetConfig(); + SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len); + ~SetConfig() { + } + ; +}; + +/** + OpenFlow 1.3 OFPT_PACKET_OUT message. + */ +class PacketOut: public PacketOutCommon { +private: + uint32_t in_port_; +public: + PacketOut(); + PacketOut(uint32_t xid, uint32_t buffer_id, uint32_t in_port); + bool operator==(const PacketOut &other) const; + bool operator!=(const PacketOut &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t in_port() { + return this->in_port_; + } + void in_port(uint32_t in_port) { + this->in_port_ = in_port; + } +}; + +/** + OpenFlow 1.3 OFPT_PACKET_IN message. + */ +class PacketIn: public PacketInCommon { +private: + uint8_t table_id_; + uint64_t cookie_; + of13::Match match_; +public: + PacketIn(); + PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t total_len, + uint8_t reason, uint8_t table_id, uint64_t cookie); + ~PacketIn() { + } + ; + virtual uint16_t length(); + bool operator==(const PacketIn &other) const; + bool operator!=(const PacketIn &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() const { + return this->table_id_; + } + uint64_t cookie() const { + return this->cookie_; + } + of13::Match& match() { + return this->match_; + } + const of13::Match& match() const { + return this->match_; + } + ; + OXMTLV * get_oxm_field(uint8_t field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); +}; + +/** + OpenFlow 1.3 OFPT_FLOW_MOD message. + */ +class FlowMod: public FlowModCommon { +private: + uint8_t command_; + uint64_t cookie_mask_; + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + of13::Match match_; + InstructionSet instructions_; +public: + FlowMod(); + FlowMod(uint32_t xid, uint64_t cookie, uint64_t cookie_mask, + uint8_t table_id, uint8_t command, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint32_t out_port, uint32_t out_group, uint16_t flags); + ~FlowMod() { + } + bool operator==(const FlowMod &other) const; + bool operator!=(const FlowMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + virtual uint16_t length(); + uint8_t command(){ + return this->command_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + of13::Match match() { + return this->match_; + } + of13::InstructionSet instructions() { + return this->instructions_; + } + OXMTLV * get_oxm_field(uint8_t field); + void command(uint8_t command){ + this->command_ = command; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); + void instructions(InstructionSet instructions); + void add_instruction(Instruction &inst); + void add_instruction(Instruction* inst); +}; + +/** + OpenFlow 1.3 OFPT_FLOW_REMOVED message. + */ +class FlowRemoved: public FlowRemovedCommon { +private: + uint8_t table_id_; + uint16_t hard_timeout_; + of13::Match match_; +public: + FlowRemoved(); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count); + FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count, of13::Match); + ~FlowRemoved() { + } + virtual uint16_t length(); + bool operator==(const FlowRemoved &other) const; + bool operator!=(const FlowRemoved &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() { + return this->table_id_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + of13::Match match() { + return this->match_; + } + void match(of13::Match match) { + this->match_ = match; + } +}; + +/** + OpenFlow 1.3 OFPT_PORT_STATUS message. + */ +class PortStatus: public PortStatusCommon { +private: + of13::Port desc_; +public: + PortStatus(); + PortStatus(uint32_t xid, uint8_t reason, of13::Port desc); + ~PortStatus() { + } + bool operator==(const PortStatus &other) const; + bool operator!=(const PortStatus &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Port desc() { + return this->desc_; + } + void desc(of13::Port desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.3 OFPT_PORT_MOD message. + */ +class PortMod: public PortModCommon { +private: + uint32_t port_no_; +public: + PortMod(); + PortMod(uint32_t xid, uint32_t port_no, EthAddress hw_addr, uint32_t config, + uint32_t mask, uint32_t advertise); + ~PortMod() { + } + bool operator==(const PortMod &other) const; + bool operator!=(const PortMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port_no() { + return this->port_no_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.3 OFPT_GROUP_MOD message. + */ +class GroupMod: public OFMsg { +private: + uint16_t command_; + uint8_t group_type_; + uint32_t group_id_; + std::vector buckets_; +public: + GroupMod(); + GroupMod(uint32_t xid, uint16_t command, uint8_t type, uint32_t group_id); + GroupMod(uint32_t xid, uint16_t command, uint8_t type, uint32_t group_id, + std::vector buckets); + ~GroupMod() { + } + bool operator==(const GroupMod &other) const; + bool operator!=(const GroupMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command() { + return this->command_; + } + uint8_t type() { + return this->type_; + } + uint32_t group_id() { + return this->group_id_; + } + std::vector buckets() { + return this->buckets_; + } + void commmand(uint16_t command) { + this->command_ = command; + } + void group_type(uint8_t type) { + this->group_type_ = type; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } + void buckets(std::vector buckets); + void add_bucket(Bucket bucket); + size_t buckets_len(); +}; + +/** + OpenFlow 1.3 OFPT_TABLE_MOD message. + */ +class TableMod: public OFMsg { +private: + uint8_t table_id_; + uint32_t config_; +public: + TableMod(); + TableMod(uint32_t xid, uint8_t table_id, uint32_t config); + ~TableMod() { + } + bool operator==(const TableMod &other) const; + bool operator!=(const TableMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint8_t table_id() { + return this->table_id_; + } + uint32_t config() { + return this->config_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void config(uint32_t config) { + this->config_ = config; + } +}; + +/** + OpenFlow 1.3 OFPT_MULTIPART_REQUEST message header. Multipart request + messages should inherit from this class. + */ +class MultipartRequest: public OFMsg { +protected: + uint16_t mpart_type_; + uint16_t flags_; +public: + MultipartRequest(); + MultipartRequest(uint16_t type); + MultipartRequest(uint32_t xid, uint16_t type, uint16_t flags); + virtual ~MultipartRequest() { + } + bool operator==(const MultipartRequest &other) const; + bool operator!=(const MultipartRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t mpart_type() { + return this->mpart_type_; + } + uint16_t flags() { + return this->flags_; + } + void type(uint16_t type) { + this->mpart_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.3 OFPT_MULTIPART_REPLY message header. Multipart reply + messages should inherit from this class. + */ +class MultipartReply: public OFMsg { +protected: + uint16_t mpart_type_; + uint16_t flags_; +public: + MultipartReply(); + MultipartReply(uint16_t type); + MultipartReply(uint32_t xid, uint16_t type, uint16_t flags); + virtual ~MultipartReply() { + } + bool operator==(const MultipartReply &other) const; + bool operator!=(const MultipartReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t mpart_type() { + return this->mpart_type_; + } + uint16_t flags() { + return this->flags_; + } + void type(uint16_t type) { + this->mpart_type_ = type; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + OpenFlow 1.3 OFPMP_DESC multipart request. + */ +class MultipartRequestDesc: public MultipartRequest { +public: + MultipartRequestDesc(); + MultipartRequestDesc(uint32_t xid, uint16_t flags); + ~MultipartRequestDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_DESC multipart reply. + */ +class MultipartReplyDesc: public MultipartReply { +private: + SwitchDesc desc_; +public: + MultipartReplyDesc(); + MultipartReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc); + MultipartReplyDesc(uint32_t xid, uint16_t flags, std::string mfr_desc, + std::string hw_desc, std::string sw_desc, std::string serial_num, + std::string dp_desc); + ~MultipartReplyDesc() { + } + bool operator==(const MultipartReplyDesc &other) const; + bool operator!=(const MultipartReplyDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + SwitchDesc desc() { + return this->desc_; + } + void set_desc(SwitchDesc desc) { + this->desc_ = desc; + } +}; + +/** + OpenFlow 1.3 OFPMP_FLOW multipart request. + */ +class MultipartRequestFlow: public MultipartRequest { +private: + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + uint64_t cookie_; + uint64_t cookie_mask_; + of13::Match match_; +public: + MultipartRequestFlow(); + MultipartRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask); + MultipartRequestFlow(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match); + ~MultipartRequestFlow() { + } + bool operator==(const MultipartRequestFlow &other) const; + bool operator!=(const MultipartRequestFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV* field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } +}; + +/** + OpenFlow 1.3 OFPMP_FLOW multipart reply. + */ +class MultipartReplyFlow: public MultipartReply { +private: + std::vector flow_stats_; +public: + MultipartReplyFlow(); + MultipartReplyFlow(uint32_t xid, uint16_t flags); + MultipartReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats); + ~MultipartReplyFlow() { + } + bool operator==(const MultipartReplyFlow &other) const; + bool operator!=(const MultipartReplyFlow &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector flow_stats() { + return this->flow_stats_; + } + void flow_stats(std::vector flow_stats); + void add_flow_stats(of13::FlowStats); +}; + +/** + OpenFlow 1.3 OFPMP_AGGREGATE multipart request. + */ +class MultipartRequestAggregate: public MultipartRequest { +private: + uint8_t table_id_; + uint32_t out_port_; + uint32_t out_group_; + uint64_t cookie_; + uint64_t cookie_mask_; + of13::Match match_; +public: + MultipartRequestAggregate(); + MultipartRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask); + MultipartRequestAggregate(uint32_t xid, uint16_t flags, uint8_t table_id, + uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match); + ~MultipartRequestAggregate() { + } + virtual uint16_t length(); + bool operator==(const MultipartRequestAggregate &other) const; + bool operator!=(const MultipartRequestAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::Match match() { + return this->match_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t out_port() { + return this->out_port_; + } + uint32_t out_group() { + return this->out_group_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t cookie_mask() { + return this->cookie_mask_; + } + void match(of13::Match match); + void add_oxm_field(OXMTLV &field); + void add_oxm_field(OXMTLV *field); + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void out_port(uint32_t out_port) { + this->out_port_ = out_port; + } + void out_group(uint32_t out_group) { + this->out_group_ = out_group; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void cookie_mask(uint64_t cookie_mask) { + this->cookie_mask_ = cookie_mask; + } +}; + +/** + OpenFlow 1.3 OFPMP_AGGREGATE multipart reply. + */ +class MultipartReplyAggregate: public MultipartReply { +private: + uint64_t packet_count_; + uint64_t byte_count_; + uint32_t flow_count_; +public: + MultipartReplyAggregate(); + MultipartReplyAggregate(uint32_t xid, uint16_t flags, uint64_t packet_count, + uint64_t byte_count, uint32_t flow_count); + ~MultipartReplyAggregate() { + } + bool operator==(const MultipartReplyAggregate &other) const; + bool operator!=(const MultipartReplyAggregate &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + uint32_t flow_count() { + return this->flow_count_; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } + void flow_count(uint32_t flow_count) { + this->flow_count_ = flow_count; + } +}; + +/** + OpenFlow 1.3 OFPMP_TABLE multipart request. + */ +class MultipartRequestTable: public MultipartRequest { +public: + MultipartRequestTable(); + MultipartRequestTable(uint32_t xid, uint16_t flags); + ~MultipartRequestTable() { + } + ; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_TABLE multipart reply. + */ +class MultipartReplyTable: public MultipartReply { +private: + std::vector table_stats_; +public: + MultipartReplyTable(); + MultipartReplyTable(uint32_t xid, uint16_t flags); + MultipartReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats); + ~MultipartReplyTable() { + } + bool operator==(const MultipartReplyTable &other) const; + bool operator!=(const MultipartReplyTable &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_stats() { + return this->table_stats_; + } + void table_stats(std::vector table_stats); + void add_table_stat(of13::TableStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_STATS multipart request. + */ +class MultipartRequestPortStats: public MultipartRequest { +private: + uint32_t port_no_; +public: + MultipartRequestPortStats(); + MultipartRequestPortStats(uint32_t xid, uint16_t flags, uint32_t port_no); + ~MultipartRequestPortStats() { + } + bool operator==(const MultipartRequestPortStats &other) const; + bool operator!=(const MultipartRequestPortStats &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port_no() { + return this->port_no_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } +}; + +/** + OpenFlow 1.3 OFPMP_PORT_STATS multipart reply. + */ +class MultipartReplyPortStats: public MultipartReply { +private: + std::vector port_stats_; +public: + MultipartReplyPortStats(); + MultipartReplyPortStats(uint32_t xid, uint16_t flags); + MultipartReplyPortStats(uint32_t xid, uint16_t flags, + std::vector port_stats); + ~MultipartReplyPortStats() { + } + bool operator==(const MultipartReplyPortStats &other) const; + bool operator!=(const MultipartReplyPortStats &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector port_stats() { + return this->port_stats_; + } + void port_stats(std::vector port_stats); + void add_port_stat(of13::PortStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_QUEUE multipart request. + */ +class MultipartRequestQueue: public MultipartRequest { +private: + uint32_t port_no_; + uint32_t queue_id_; +public: + MultipartRequestQueue(); + MultipartRequestQueue(uint32_t xid, uint16_t flags, uint32_t port_no, + uint32_t queue_id); + ~MultipartRequestQueue() { + } + bool operator==(const MultipartRequestQueue &other) const; + bool operator!=(const MultipartRequestQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t port_no() { + return this->port_no_; + } + uint32_t queue_id() { + return this->queue_id_; + } + void port_no(uint32_t port_no) { + this->port_no_ = port_no; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_QUEUE multipart reply. + */ +class MultipartReplyQueue: public MultipartReply { +private: + std::vector queue_stats_; +public: + MultipartReplyQueue(); + MultipartReplyQueue(uint32_t xid, uint16_t flags); + MultipartReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats); + ~MultipartReplyQueue() { + } + bool operator==(const MultipartReplyQueue &other) const; + bool operator!=(const MultipartReplyQueue &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->queue_stats_; + } + void queue_stats(std::vector queue_stats_); + void add_queue_stat(of13::QueueStats stat); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP multipart request. + */ +class MultipartRequestGroup: public MultipartRequest { +private: + uint32_t group_id_; +public: + MultipartRequestGroup(); + MultipartRequestGroup(uint32_t xid, uint16_t flags, uint32_t group_id); + ~MultipartRequestGroup() { + } + bool operator==(const MultipartRequestGroup &other) const; + bool operator!=(const MultipartRequestGroup &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t group_id() { + return this->group_id_; + } + void group_id(uint32_t group_id) { + this->group_id_ = group_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_GROUP multipart reply. + */ +class MultipartReplyGroup: public MultipartReply { +private: + std::vector group_stats_; +public: + MultipartReplyGroup(); + MultipartReplyGroup(uint32_t xid, uint16_t flags); + MultipartReplyGroup(uint32_t xid, uint16_t flags, + std::vector group_stats); + ~MultipartReplyGroup() { + } + bool operator==(const MultipartReplyGroup &other) const; + bool operator!=(const MultipartReplyGroup &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->group_stats_; + } + void group_stats(std::vector group_stats); + void add_group_stats(of13::GroupStats stat); + size_t group_stats_len(); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_DESC multipart request. + */ +class MultipartRequestGroupDesc: public MultipartRequest { +public: + MultipartRequestGroupDesc(); + MultipartRequestGroupDesc(uint32_t xid, uint16_t flags); + ~MultipartRequestGroupDesc() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_DESC multipart reply. + */ +class MultipartReplyGroupDesc: public MultipartReply { +private: + std::vector group_desc_; +public: + MultipartReplyGroupDesc(); + MultipartReplyGroupDesc(uint32_t xid, uint16_t flags); + MultipartReplyGroupDesc(uint32_t xid, uint16_t flags, + std::vector group_desc); + ~MultipartReplyGroupDesc() { + } + bool operator==(const MultipartReplyGroupDesc &other) const; + bool operator!=(const MultipartReplyGroupDesc &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector queue_stats() { + return this->group_desc_; + } + void group_desc(std::vector group_desc); + void add_group_desc(of13::GroupDesc stat); + size_t desc_len(); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_FEATURES multipart request. + */ +class MultipartRequestGroupFeatures: public MultipartRequest { +public: + MultipartRequestGroupFeatures(); + MultipartRequestGroupFeatures(uint32_t xid, uint16_t flags); + ~MultipartRequestGroupFeatures() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_GROUP_FEATURES multipart reply. + */ +class MultipartReplyGroupFeatures: public MultipartReply { +private: + of13::GroupFeatures features_; +public: + MultipartReplyGroupFeatures(); + MultipartReplyGroupFeatures(uint32_t xid, uint16_t flags, + of13::GroupFeatures features); + ~MultipartReplyGroupFeatures() { + } + bool operator==(const MultipartReplyGroupFeatures &other) const; + bool operator!=(const MultipartReplyGroupFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + of13::GroupFeatures features() { + return this->features_; + } + void features(of13::GroupFeatures features) { + this->features_ = features; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER multipart request. + */ +class MultipartRequestMeter: public MultipartRequest { +private: + uint32_t meter_id_; +public: + MultipartRequestMeter(); + MultipartRequestMeter(uint32_t xid, uint16_t flags, uint32_t meter_id); + bool operator==(const MultipartRequestMeter &other) const; + bool operator!=(const MultipartRequestMeter &other) const; + ~MultipartRequestMeter() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER multipart reply. + */ +class MultipartReplyMeter: public MultipartReply { +private: + std::vector meter_stats_; +public: + MultipartReplyMeter(); + MultipartReplyMeter(uint32_t xid, uint16_t flags); + MultipartReplyMeter(uint32_t xid, uint16_t flags, + std::vector meter_stats); + ~MultipartReplyMeter() { + } + bool operator==(const MultipartReplyMeter &other) const; + bool operator!=(const MultipartReplyMeter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector meter_stats() { + return this->meter_stats_; + } + void meter_stats(std::vector meter_stats); + void add_meter_stats(MeterStats stats); + size_t meter_stats_len(); +}; + +/** + OpenFlow 1.3 OFPMP_METER_CONFIG multipart request. + */ +class MultipartRequestMeterConfig: public MultipartRequest { +private: + uint32_t meter_id_; +public: + MultipartRequestMeterConfig(); + MultipartRequestMeterConfig(uint32_t xid, uint16_t flags, uint32_t meter_id); + bool operator==(const MultipartRequestMeterConfig &other) const; + bool operator!=(const MultipartRequestMeterConfig &other) const; + ~MultipartRequestMeterConfig() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t meter_id() { + return this->meter_id_; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } +}; + +/** + OpenFlow 1.3 OFPMP_METER_CONFIG multipart reply. + */ +class MultipartReplyMeterConfig: public MultipartReply { + std::vector meter_config_; +public: + MultipartReplyMeterConfig(); + MultipartReplyMeterConfig(uint32_t xid, uint16_t flags); + MultipartReplyMeterConfig(uint32_t xid, uint16_t flags, + std::vector meter_config); + ~MultipartReplyMeterConfig() { + } + bool operator==(const MultipartReplyMeterConfig &other) const; + bool operator!=(const MultipartReplyMeterConfig &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector meter_config() { + return this->meter_config_; + } + void meter_config(std::vector meter_config); + void add_meter_config(MeterConfig config); + size_t meter_config_len(); +}; + +/** + OpenFlow 1.3 OFPMP_METER_FEATURES multipart request. + */ +class MultipartRequestMeterFeatures: public MultipartRequest { +public: + MultipartRequestMeterFeatures(); + MultipartRequestMeterFeatures(uint32_t xid, uint16_t flags); + ~MultipartRequestMeterFeatures() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_METER_FEATURES multipart reply. + */ +class MultipartReplyMeterFeatures: public MultipartReply { +private: + MeterFeatures meter_features_; +public: + MultipartReplyMeterFeatures(); + MultipartReplyMeterFeatures(uint32_t xid, uint16_t flags, + MeterFeatures features); + ~MultipartReplyMeterFeatures() { + } + bool operator==(const MultipartReplyMeterFeatures &other) const; + bool operator!=(const MultipartReplyMeterFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + MeterFeatures meter_features() { + return this->meter_features_; + } + void meter_features(MeterFeatures meter_features) { + this->meter_features_ = meter_features; + } +}; + +/** + OpenFlow 1.3 OFPMP_TABLE_FEATURES multipart request. + */ +class MultipartRequestTableFeatures: public MultipartRequest { +private: + std::vector tables_features_; +public: + MultipartRequestTableFeatures(); + MultipartRequestTableFeatures(uint32_t xid, uint16_t flags); + MultipartRequestTableFeatures(uint32_t xid, uint16_t flags, + std::vector table_features); + ~MultipartRequestTableFeatures() { + } + bool operator==(const MultipartRequestTableFeatures &other) const; + bool operator!=(const MultipartRequestTableFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector tables_features() { + return this->tables_features_; + } + void tables_features(std::vector tables_features); + void add_table_features(TableFeatures table_feature); +}; + +/** + OpenFlow 1.3 OFPMP_TABLE_FEATURES multipart reply. + */ +class MultipartReplyTableFeatures: public MultipartReply { +private: + std::vector tables_features_; +public: + MultipartReplyTableFeatures(); + MultipartReplyTableFeatures(uint32_t xid, uint16_t flags); + MultipartReplyTableFeatures(uint32_t xid, uint16_t flags, + std::vector table_features); + ~MultipartReplyTableFeatures() { + } + bool operator==(const MultipartReplyTableFeatures &other) const; + bool operator!=(const MultipartReplyTableFeatures &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector table_features() { + return this->tables_features_; + } + void tables_features(std::vector tables_features); + void add_table_features(TableFeatures table_feature); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_DESC multipart request. + */ +class MultipartRequestPortDescription: public MultipartRequest { +public: + MultipartRequestPortDescription(); + MultipartRequestPortDescription(uint32_t xid, uint16_t flags); + ~MultipartRequestPortDescription() { + } + uint8_t* pack(); + of_error unpack(uint8_t *buffer); +}; + +/** + OpenFlow 1.3 OFPMP_PORT_DESC multipart reply. + */ +class MultipartReplyPortDescription: public MultipartReply { +private: + std::vector ports_; +public: + MultipartReplyPortDescription(); + MultipartReplyPortDescription(uint32_t xid, uint16_t flags); + MultipartReplyPortDescription(uint32_t xid, uint16_t flags, + std::vector ports); + ~MultipartReplyPortDescription() { + } + bool operator==(const MultipartReplyPortDescription &other) const; + bool operator!=(const MultipartReplyPortDescription &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + std::vector ports() { + return this->ports_; + } + void ports(std::vector ports); + void add_port(of13::Port); +}; + +/** + OpenFlow 1.3 OFPMP_EXPERIMENTER multipart request. + Multipart request experimenter messages should inherit from this class. + */ +class MultipartRequestExperimenter: public MultipartRequest { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + MultipartRequestExperimenter(); + MultipartRequestExperimenter(uint32_t xid, uint16_t flags, + uint32_t experimenter, uint32_t exp_type); + virtual ~MultipartRequestExperimenter() { + } + bool operator==(const MultipartRequestExperimenter &other) const; + bool operator!=(const MultipartRequestExperimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPMP_EXPERIMENTER multipart reply. + Multipart reply experimenter messages should inherit from this class. + */ +class MultipartReplyExperimenter: public MultipartReply { +protected: + uint32_t experimenter_; + uint32_t exp_type_; +public: + MultipartReplyExperimenter(); + MultipartReplyExperimenter(uint32_t xid, uint16_t flags, + uint32_t experimenter, uint32_t exp_type); + virtual ~MultipartReplyExperimenter() { + } + bool operator==(const MultipartReplyExperimenter &other) const; + bool operator!=(const MultipartReplyExperimenter &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t experimenter() { + return this->experimenter_; + } + uint32_t exp_type() { + return this->exp_type_; + } +}; + +/** + OpenFlow 1.3 OFPT_BARRIER_REQUEST message. + */ +class BarrierRequest: public OFMsg { +public: + BarrierRequest(); + BarrierRequest(uint32_t xid); + ~BarrierRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_BARRIER_REPLY message*/ +class BarrierReply: public OFMsg { +public: + BarrierReply(); + BarrierReply(uint32_t xid); + ~BarrierReply() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_QUEUE_GET_CONFIG_REQUEST message. + */ +class QueueGetConfigRequest: public OFMsg { +private: + uint32_t port_; +public: + QueueGetConfigRequest(); + QueueGetConfigRequest(uint32_t xid, uint32_t port); + ~QueueGetConfigRequest() { + } + bool operator==(const QueueGetConfigRequest &other) const; + bool operator!=(const QueueGetConfigRequest &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port() { + return this->port_; + } + void port(uint32_t port) { + this->port_ = port; + } +}; + +/** + OpenFlow 1.3 OFPT_QUEUE_GET_CONFIG_REPLY message. + */ +class QueueGetConfigReply: public OFMsg { +private: + uint32_t port_; + std::list queues_; +public: + QueueGetConfigReply(); + QueueGetConfigReply(uint32_t xid, uint32_t port); + QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues); + ~QueueGetConfigReply() { + } + bool operator==(const QueueGetConfigReply &other) const; + bool operator!=(const QueueGetConfigReply &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint32_t port() { + return this->port_; + } + std::list queues() { + return this->queues_; + } + void port(uint32_t port) { + this->port_ = port; + } + void queues(std::list queues); + void add_queue(PacketQueue queue); + size_t queues_len(); +}; + +/** + OpenFlow 1.3 OFPT_ROLE_REQUEST message. + */ +class RoleRequest: public RoleCommon { +public: + RoleRequest(); + RoleRequest(uint32_t xid, uint32_t role, uint64_t generation_id); + ~RoleRequest() { + } +}; + +/** + OpenFlow 1.3 OFPT_ROLE_REPLY message. + */ +class RoleReply: public RoleCommon { +public: + RoleReply(); + RoleReply(uint32_t xid, uint32_t role, uint64_t generation_id); + ~RoleReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_GET_ASYNC_REQUEST message. + */ +class GetAsyncRequest: public OFMsg { +public: + GetAsyncRequest(); + GetAsyncRequest(uint32_t xid); + ~GetAsyncRequest() { + } + uint8_t* pack(); + of_error unpack(uint8_t* buffer); +}; + +/** + OpenFlow 1.3 OFPT_GET_ASYNC_REPLY message. + */ +class GetAsyncReply: public AsyncConfigCommon { +public: + GetAsyncReply(); + GetAsyncReply(uint32_t xid); + GetAsyncReply(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + ~GetAsyncReply() { + } +}; + +/** + OpenFlow 1.3 OFPT_SET_ASYNC message. + */ +class SetAsync: public AsyncConfigCommon { +public: + SetAsync(); + SetAsync(uint32_t xid); + SetAsync(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask); + ~SetAsync() { + } +}; + +class MeterMod: public OFMsg { +private: + uint16_t command_; + uint16_t flags_; + uint32_t meter_id_; + MeterBandList bands_; + +public: + MeterMod(); + MeterMod(uint32_t xid, uint16_t command, uint16_t flags, uint32_t meter_id); + MeterMod(uint32_t xid, uint16_t command, uint16_t flags, uint32_t meter_id, + MeterBandList bands); + ~MeterMod() { + } + bool operator==(const MeterMod &other) const; + bool operator!=(const MeterMod &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t command() { + return this->command_; + } + uint16_t flags() { + return this->flags_; + } + uint32_t meter_id() { + return this->meter_id_; + } + MeterBandList bands() { + return this->bands_; + } + void command(uint16_t command) { + this->command_ = command; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } + void meter_id(uint32_t meter_id) { + this->meter_id_ = meter_id; + } + void bands(MeterBandList bands); + void add_band(MeterBand * band); +}; + +} // end of namespace of13 +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/ofcommon/action.hh b/include/libfluid-msg/ofcommon/action.hh new file mode 100644 index 00000000..7094f6c9 --- /dev/null +++ b/include/libfluid-msg/ofcommon/action.hh @@ -0,0 +1,138 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 ACTION_H +#define ACTION_H + +#include +#include +#include "../util/util.h" +#include "openflow-common.hh" + +namespace fluid_msg { + +class Action { +protected: + uint16_t type_; + uint16_t length_; +public: + Action(); + Action(uint16_t type, uint16_t length); + virtual ~Action() { + } + ; + virtual size_t pack(uint8_t *buffer); + virtual of_error unpack(uint8_t *buffer); + virtual bool equals(const Action & other); + virtual bool operator==(const Action &other) const; + virtual bool operator!=(const Action &other) const; + virtual Action* clone() { + return new Action(*this); + } + virtual uint16_t set_order() const { + return 0; + } + uint16_t type() { + return this->type_; + } + uint16_t length() { + return this->length_; + } + void type(uint16_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + static Action * make_of10_action(uint16_t type); + static Action * make_of13_action(uint16_t type); + static bool delete_all(Action * action) { + delete action; + return true; + } + +}; + +class ActionList { +private: + uint16_t length_; + std::list action_list_; +public: + ActionList() + : length_(0) { + } + ; + ActionList(std::list action_list); + ActionList(const ActionList &other); + bool operator==(const ActionList &other) const; + bool operator!=(const ActionList &other) const; + ActionList& operator=(ActionList other); + ~ActionList(); + size_t pack(uint8_t *buffer); + of_error unpack10(uint8_t *buffer); + of_error unpack13(uint8_t *buffer); + friend void swap(ActionList& first, ActionList& second); + uint16_t length() { + return this->length_; + } + std::list action_list(){ + return this->action_list_; + } + void add_action(Action &action); + void add_action(Action *act); + void length(uint16_t length) { + this->length_ = length; + } +}; + +struct comp_action_set_order { + bool operator()(Action * lhs, Action* rhs) const { + return lhs->set_order() < rhs->set_order(); + } +}; + +class ActionSet { +private: + uint16_t length_; + std::set action_set_; +public: + ActionSet() + : length_(0) { + } + ; + ActionSet(std::set action_set); + ActionSet(const ActionSet &other); + bool operator==(const ActionSet &other) const; + bool operator!=(const ActionSet &other) const; + ActionSet& operator=(ActionSet other); + ~ActionSet(); + size_t pack(uint8_t *buffer); + of_error unpack(uint8_t *buffer); + friend void swap(ActionSet& first, ActionSet& second); + uint16_t length() { + return this->length_; + } + std::set action_set(){ + return this->action_set_; + } + void add_action(Action &action); + void add_action(Action *act); + void length(uint16_t length) { + this->length_ = length; + } +}; + +} //End of namespace fluid_msg +#endif diff --git a/include/libfluid-msg/ofcommon/common.hh b/include/libfluid-msg/ofcommon/common.hh new file mode 100644 index 00000000..e3510782 --- /dev/null +++ b/include/libfluid-msg/ofcommon/common.hh @@ -0,0 +1,559 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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. + +#pragma once + +#include +#include +#include "action.hh" +#include "../util/util.h" +#include "../util/ethaddr.hh" +#include "../util/ipaddr.hh" + +namespace fluid_msg { + +class PortCommon { +protected: + EthAddress hw_addr_; + std::string name_; + uint32_t config_; + uint32_t state_; + uint32_t curr_; + uint32_t advertised_; + uint32_t supported_; + uint32_t peer_; +public: + PortCommon(); + PortCommon(EthAddress hw_addr, std::string name, uint32_t config, + uint32_t state, uint32_t curr, uint32_t advertised, uint32_t supported, + uint32_t peer); + ~PortCommon() { + } + bool operator==(const PortCommon &other) const; + bool operator!=(const PortCommon &other) const; + EthAddress hw_addr() { + return this->hw_addr_; + } + std::string name() { + return this->name_; + } + uint32_t config() { + return this->config_; + } + uint32_t state() { + return this->state_; + } + uint32_t curr() { + return this->curr_; + } + uint32_t advertised() { + return this->advertised_; + } + uint32_t supported() { + return this->supported_; + } + uint32_t peer() { + return this->peer_; + } + void hw_addr(EthAddress hw_addr) { + this->hw_addr_ = hw_addr; + } + void name(std::string name) { + this->name_ = name; + } + void config(uint32_t config) { + this->config_ = config; + } + void state(uint32_t state) { + this->state_ = state; + } + void curr(uint32_t curr) { + this->curr_ = curr; + } + void advertised(uint32_t advertised) { + this->advertised_ = advertised; + } + void supported(uint32_t supported) { + this->supported_ = supported; + } + void peer(uint32_t peer) { + this->peer_ = peer; + } + +}; + +class QueueProperty { +protected: + uint16_t property_; + uint16_t len_; +public: + QueueProperty(); + QueueProperty(uint16_t property); + virtual ~QueueProperty() { + } + ; + virtual bool equals(const QueueProperty & other); + virtual bool operator==(const QueueProperty &other) const; + virtual bool operator!=(const QueueProperty &other) const; + virtual QueueProperty* clone() { + return new QueueProperty(*this); + } + virtual size_t pack(uint8_t* buffer); + virtual of_error unpack(uint8_t* buffer); + uint16_t property() { + return this->property_; + } + uint16_t len() { + return this->len_; + } + void property(uint16_t property) { + this->property_ = property; + } + static QueueProperty* make_queue_of10_property(uint16_t property); + static QueueProperty* make_queue_of13_property(uint16_t property); + static bool delete_all(QueueProperty * prop) { + delete prop; + return true; + } +}; + +class QueuePropertyList { +private: + uint16_t length_; + std::list property_list_; +public: + QueuePropertyList() + : length_(0) { + } + ; + QueuePropertyList(std::list prop_list); + QueuePropertyList(const QueuePropertyList &other); + QueuePropertyList& operator=(QueuePropertyList other); + ~QueuePropertyList(); + bool operator==(const QueuePropertyList &other) const; + bool operator!=(const QueuePropertyList &other) const; + size_t pack(uint8_t* buffer); + of_error unpack10(uint8_t* buffer); + of_error unpack13(uint8_t* buffer); + friend void swap(QueuePropertyList& first, QueuePropertyList& second); + uint16_t length() { + return this->length_; + } + std::list property_list() { + return this->property_list_; + } + void add_property(QueueProperty *prop); + void length(uint16_t length) { + this->length_ = length; + } +}; + +class QueuePropRate: public QueueProperty { +protected: + uint16_t rate_; +public: + QueuePropRate(); + QueuePropRate(uint16_t property); + QueuePropRate(uint16_t property, uint16_t rate); + ~QueuePropRate() { + } + ; + virtual bool equals(const QueueProperty & other); + virtual QueuePropRate* clone() { + return new QueuePropRate(*this); + } + uint16_t rate() { + return this->rate_; + } + void rate(uint16_t rate) { + this->rate_ = rate; + } +}; + +class SwitchDesc { +private: + std::string mfr_desc_; + std::string hw_desc_; + std::string sw_desc_; + std::string serial_num_; + std::string dp_desc_; +public: + SwitchDesc() { + } + ; + SwitchDesc(std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc); + ~SwitchDesc() { + } + ; + bool operator==(const SwitchDesc &other) const; + bool operator!=(const SwitchDesc &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + std::string mfr_desc() { + return this->mfr_desc_; + } + std::string hw_desc() { + return this->hw_desc_; + } + std::string sw_desc() { + return this->sw_desc_; + } + std::string serial_num() { + return this->serial_num_; + } + std::string dp_desc() { + return this->dp_desc_; + } + void mfr_desc(std::string mfr_desc) { + this->mfr_desc_ = mfr_desc; + } + void hw_desc(std::string hw_desc) { + this->hw_desc_ = hw_desc; + } + void sw_desc(std::string sw_desc) { + this->sw_desc_ = sw_desc; + } + void serial_num(std::string serial_num) { + this->serial_num_ = serial_num; + } + void dp_desc(std::string dp_desc) { + this->dp_desc_ = dp_desc; + } + +}; + +/* Queue description*/ +class PacketQueueCommon { +protected: + uint32_t queue_id_; + uint16_t len_; + QueuePropertyList properties_; +public: + PacketQueueCommon(); + PacketQueueCommon(uint32_t queue_id); + virtual ~PacketQueueCommon() { + } + ; + bool operator==(const PacketQueueCommon &other) const; + bool operator!=(const PacketQueueCommon &other) const; + uint32_t queue_id() { + return this->queue_id_; + } + uint16_t len() { + return this->len_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } + void property(QueuePropertyList properties); + void add_property(QueueProperty* qp); +}; + +class FlowStatsCommon { +protected: + uint16_t length_; + uint8_t table_id_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + uint16_t priority_; + uint16_t idle_timeout_; + uint16_t hard_timeout_; + uint64_t cookie_; + uint64_t packet_count_; + uint64_t byte_count_; +public: + FlowStatsCommon(); + FlowStatsCommon(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count); + ~FlowStatsCommon() { + } + ; + bool operator==(const FlowStatsCommon &other) const; + bool operator!=(const FlowStatsCommon &other) const; + uint16_t length() { + return this->length_; + } + uint8_t table_id() { + return this->table_id_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + uint16_t priority() { + return this->priority_; + } + uint16_t idle_timeout() { + return this->idle_timeout_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + uint64_t cookie() { + return this->cookie_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void packet_count(uint16_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } +}; + +class TableStatsCommon { +protected: + uint8_t table_id_; + uint32_t active_count_; + uint64_t lookup_count_; + uint64_t matched_count_; +public: + TableStatsCommon(); + TableStatsCommon(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count); + ~TableStatsCommon() { + } + ; + bool operator==(const TableStatsCommon &other) const; + bool operator!=(const TableStatsCommon &other) const; + uint8_t table_id() { + return this->table_id_; + } + uint32_t active_count() { + return this->active_count_; + } + uint64_t lookup_count() { + return this->lookup_count_; + } + uint64_t matched_count() { + return this->matched_count_; + } + void table_id(uint8_t table_id) { + this->table_id_ = table_id; + } + void active_count(uint32_t active_count) { + this->active_count_ = active_count; + } + void lookup_count(uint64_t lookup_count) { + this->lookup_count_ = lookup_count; + } + void matched_count(uint64_t matched_count) { + this->matched_count_ = matched_count; + } +}; + +struct port_rx_tx_stats { + 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. */ + + bool operator==(const struct port_rx_tx_stats other) const { + return ((this->rx_packets == other.rx_packets) + && (this->tx_packets == other.tx_packets) + && (this->rx_bytes == other.rx_bytes) + && (this->tx_bytes == other.tx_bytes) + && (this->rx_dropped == other.rx_dropped) + && (this->tx_dropped == other.tx_dropped)); + } +}; + +struct port_err_stats { + 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. */ + + bool operator==(const struct port_err_stats other) const { + return ((this->rx_errors == other.rx_errors) + && (this->tx_errors == other.tx_errors) + && (this->rx_frame_err == other.rx_frame_err) + && (this->rx_over_err == other.rx_over_err) + && (this->rx_crc_err == other.rx_crc_err)); + } +}; + +class PortStatsCommon { +protected: + struct port_rx_tx_stats rx_tx_stats; + struct port_err_stats err_stats; + uint64_t collisions_; /* Number of collisions. */ +public: + PortStatsCommon(); + PortStatsCommon(struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions); + ~PortStatsCommon() { + } + ; + bool operator==(const PortStatsCommon &other) const; + bool operator!=(const PortStatsCommon &other) const; + size_t pack(uint8_t* buffer); + of_error unpack(uint8_t* buffer); + uint64_t rx_packets() { + return this->rx_tx_stats.rx_packets; + } + uint64_t tx_packets() { + return this->rx_tx_stats.tx_packets; + } + uint64_t rx_bytes() { + return this->rx_tx_stats.rx_bytes; + } + uint64_t tx_bytes() { + return this->rx_tx_stats.tx_bytes; + } + uint64_t rx_dropped() { + return this->rx_tx_stats.rx_dropped; + } + uint64_t tx_dropped() { + return this->rx_tx_stats.tx_dropped; + } + uint64_t rx_errors() { + return this->err_stats.rx_errors; + } + uint64_t tx_errors() { + return this->err_stats.tx_errors; + } + uint64_t rx_frame_err() { + return this->err_stats.rx_frame_err; + } + uint64_t rx_over_err() { + return this->err_stats.rx_over_err; + } + uint64_t rx_crc_err() { + return this->err_stats.rx_crc_err; + } + uint64_t collisions() { + return this->collisions_; + } + void rx_packets(uint64_t rx_packets) { + this->rx_tx_stats.rx_packets = rx_packets; + } + void tx_packets(uint64_t tx_packets) { + this->rx_tx_stats.tx_packets = tx_packets; + } + void rx_bytes(uint64_t rx_bytes) { + this->rx_tx_stats.rx_bytes = rx_bytes; + } + void tx_bytes(uint64_t tx_bytes) { + this->rx_tx_stats.tx_bytes = tx_bytes; + } + void rx_dropped(uint64_t rx_dropped) { + this->rx_tx_stats.rx_dropped = rx_dropped; + } + void tx_dropped(uint64_t tx_dropped) { + this->rx_tx_stats.tx_dropped = tx_dropped; + } + void rx_errors(uint64_t rx_errors) { + this->err_stats.rx_errors = rx_errors; + } + void tx_errors(uint64_t tx_errors) { + this->err_stats.tx_errors = tx_errors; + } + void rx_frame_err(uint64_t rx_frame_err) { + this->err_stats.rx_frame_err = rx_frame_err; + } + void rx_over_err(uint64_t rx_over_err) { + this->err_stats.rx_over_err = rx_over_err; + } + void rx_crc_err(uint64_t rx_crc_err) { + this->err_stats.rx_crc_err = rx_crc_err; + } + void collisions(uint64_t collisions) { + this->collisions_ = collisions; + } +}; + +class QueueStatsCommon { +protected: + uint32_t queue_id_; + uint64_t tx_bytes_; + uint64_t tx_packets_; + uint64_t tx_errors_; +public: + QueueStatsCommon(); + QueueStatsCommon(uint32_t queue_id, uint64_t tx_bytes, uint64_t tx_packets, + uint64_t tx_errors); + ~QueueStatsCommon() { + } + ; + bool operator==(const QueueStatsCommon &other) const; + bool operator!=(const QueueStatsCommon &other) const; + uint32_t queue_id() { + return this->queue_id_; + } + uint64_t tx_bytes() { + return this->tx_bytes_; + } + uint64_t tx_packets() { + return this->tx_packets_; + } + uint64_t tx_errors() { + return this->tx_errors_; + } + void queue_id(uint32_t queue_id) { + this->queue_id_ = queue_id; + } + void tx_bytes(uint64_t tx_bytes) { + this->tx_bytes_ = tx_bytes; + } + void tx_packets(uint64_t tx_packets) { + this->tx_packets_ = tx_packets; + } + void tx_errors(uint64_t tx_errors) { + this->tx_errors_ = tx_errors; + } +}; + +} // End of namespace fluid_msg diff --git a/include/libfluid-msg/ofcommon/msg.hh b/include/libfluid-msg/ofcommon/msg.hh new file mode 100644 index 00000000..24ca84ff --- /dev/null +++ b/include/libfluid-msg/ofcommon/msg.hh @@ -0,0 +1,508 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 MSG_H +#define MSG_H 1 + +#include "../util/ethaddr.hh" +#include "action.hh" +#include "openflow-common.hh" + + +namespace fluid_msg { +class Action; +} + +namespace fluid_msg { +/** + Base class for OpenFlow messages. + */ +class OFMsg { +protected: + uint8_t version_; + uint8_t type_; + uint16_t length_; + uint32_t xid_; +public: + OFMsg(uint8_t version, uint8_t type); + OFMsg(uint8_t version, uint8_t type, uint32_t xid); + OFMsg(uint8_t* buffer) { + unpack(buffer); + } + virtual ~OFMsg() { + } + virtual uint8_t* pack(); + virtual of_error unpack(uint8_t *buffer); + bool operator==(const OFMsg &other) const; + bool operator!=(const OFMsg &other) const; + uint8_t version() { + return this->version_; + } + uint8_t type() { + return this->type_; + } + //Length is virtual because we need to override + //it in some classes where the length is padding + // dependent (e.g OpenFlow 1.3 Flow Mod). + virtual uint16_t length() { + return this->length_; + } + uint32_t xid() { + return this->xid_; + } + void version(uint8_t version) { + this->version_ = version; + } + void msg_type(uint8_t type) { + this->type_ = type; + } + void length(uint16_t length) { + this->length_ = length; + } + void xid(uint32_t xid) { + this->xid_ = xid; + } + static void free_buffer(uint8_t *buffer) { + delete[] buffer; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Echo messages. + */ +class EchoCommon: public OFMsg { +private: + void *data_; + size_t data_len_; +public: + EchoCommon(uint8_t version, uint8_t type); + EchoCommon(uint8_t version, uint8_t type, uint32_t xid) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0) { + } + virtual ~EchoCommon(); + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + bool operator==(const EchoCommon &other) const; + bool operator!=(const EchoCommon &other) const; + void* data() { + return this->data_; + } + size_t data_len() { + return this->data_len_; + } + void data(void* data, size_t data_len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Error messages. + */ +class ErrorCommon: public OFMsg { +protected: + uint16_t err_type_; + uint16_t code_; + void* data_; + size_t data_len_; +public: + ErrorCommon(uint8_t version, uint8_t type); + ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, uint16_t err_type, + uint16_t code); + ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, uint16_t err_type, + uint16_t code, void* data, size_t data_len); + virtual ~ErrorCommon(); + bool operator==(const ErrorCommon &other) const; + bool operator!=(const ErrorCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t err_type() { + return this->err_type_; + } + uint16_t code() { + return this->code_; + } + void* data() { + return this->data_; + } + size_t data_len() { + return this->data_len_; + } + void err_type(uint16_t err_type) { + this->err_type_ = err_type; + } + void code(uint16_t code) { + this->code_ = code; + } + void data(void* data, size_t data_len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Features Reply messages. + */ +class FeaturesReplyCommon: public OFMsg { +protected: + uint64_t datapath_id_; + uint32_t n_buffers_; + uint8_t n_tables_; + uint32_t capabilities_; +public: + FeaturesReplyCommon(uint8_t version, uint8_t type); + FeaturesReplyCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t datapath_id, uint32_t n_buffers, uint8_t n_tables, + uint32_t capabilities); + virtual ~FeaturesReplyCommon() { + } + bool operator==(const FeaturesReplyCommon &other) const; + bool operator!=(const FeaturesReplyCommon &other) const; + uint64_t datapath_id() { + return this->datapath_id_; + } + uint32_t n_buffers() { + return this->n_buffers_; + } + uint8_t n_tables() { + return this->n_tables_; + } + uint32_t capabilities() { + return this->capabilities_; + } + void datapath_id(uint64_t datapath_id) { + this->datapath_id_ = datapath_id; + } + void n_buffers(uint32_t n_buffers) { + this->n_buffers_ = n_buffers; + } + void n_tables(uint8_t n_tables) { + this->n_tables_ = n_tables; + } + void capabilities(uint32_t capabilities) { + this->capabilities_ = capabilities; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Features Switch Config messages. + */ +class SwitchConfigCommon: public OFMsg { +private: + uint16_t flags_; + uint16_t miss_send_len_; +public: + SwitchConfigCommon(uint8_t version, uint8_t type); + SwitchConfigCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t flags, uint16_t miss_send_len); + virtual ~SwitchConfigCommon() { + } + bool operator==(const SwitchConfigCommon &other) const; + bool operator!=(const SwitchConfigCommon &other) const; + uint8_t* pack(); + of_error unpack(uint8_t *buffer); + uint16_t flags() { + return this->flags_; + } + uint16_t miss_send_len() { + return this->miss_send_len_; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } + void miss_send_len(uint16_t miss_send_len) { + this->miss_send_len_ = miss_send_len; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Flow Mod messages. + */ +class FlowModCommon: public OFMsg { +protected: + uint64_t cookie_; + uint16_t idle_timeout_; + uint16_t hard_timeout_; + uint16_t priority_; + uint32_t buffer_id_; + uint16_t flags_; + +public: + FlowModCommon(uint8_t version, uint8_t type); + FlowModCommon(uint8_t version, uint8_t type, uint32_t xid, uint64_t cookie, + uint16_t idle_timeout, uint16_t hard_timeout, + uint16_t priority, uint32_t buffer_id, uint16_t flags); + virtual ~FlowModCommon() { + } + ; + bool operator==(const FlowModCommon &other) const; + bool operator!=(const FlowModCommon &other) const; + uint64_t cookie() { + return this->cookie_; + } + uint16_t idle_timeout() { + return this->idle_timeout_; + } + uint16_t hard_timeout() { + return this->hard_timeout_; + } + uint16_t priority() { + return this->priority_; + } + uint32_t buffer_id() { + return this->buffer_id_; + } + uint16_t flags() { + return this->flags_; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void hard_timeout(uint16_t hard_timeout) { + this->hard_timeout_ = hard_timeout; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void flags(uint16_t flags) { + this->flags_ = flags; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Packet Out messages. + */ +class PacketOutCommon: public OFMsg { +protected: + uint32_t buffer_id_; + uint16_t actions_len_; + ActionList actions_; + void* data_; + size_t data_len_; +public: + PacketOutCommon(uint8_t version, uint8_t type); + PacketOutCommon(uint8_t version, uint16_t type, uint32_t xid, + uint32_t buffer_id); + virtual ~PacketOutCommon(); + bool operator==(const PacketOutCommon &other) const; + bool operator!=(const PacketOutCommon &other) const; + uint32_t buffer_id() { + return this->buffer_id_; + } + uint16_t actions_len() { + return this->actions_len_; + } + ActionList actions() { + return this->actions_; + } + size_t data_len() { + return this->data_len_; + } + void* data() { + return this->data_; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void actions(ActionList actions); + void add_action(Action &action); + void add_action(Action *action); + void data(void* data, size_t len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Packet In messages. + */ +class PacketInCommon: public OFMsg { +protected: + uint32_t buffer_id_; + uint16_t total_len_; + uint8_t reason_; + size_t data_len_; + void* data_; +public: + PacketInCommon(uint8_t version, uint8_t type); + PacketInCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t buffer_id, uint16_t total_len, uint8_t reason); + virtual ~PacketInCommon(); + bool operator==(const PacketInCommon &other) const; + bool operator!=(const PacketInCommon &other) const; + uint32_t buffer_id() const { + return this->buffer_id_; + } + uint16_t total_len() { + return this->total_len_; + } + uint8_t reason() const { + return this->reason_; + } + void* data() const { + return this->data_; + } + size_t data_len() const { + return this->data_len_; + } + void buffer_id(uint32_t buffer_id) { + this->buffer_id_ = buffer_id; + } + void total_len(uint16_t total_len) { + this->total_len_ = total_len; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } + void data(void* data, size_t len); +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Flow Removed messages. + */ +class FlowRemovedCommon: public OFMsg { +protected: + uint64_t cookie_; + uint16_t priority_; + uint8_t reason_; + uint32_t duration_sec_; + uint32_t duration_nsec_; + uint16_t idle_timeout_; + uint64_t packet_count_; + uint64_t byte_count_; +public: + FlowRemovedCommon(uint8_t version, uint8_t type); + FlowRemovedCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t cookie, uint16_t priority, uint8_t reason, + uint32_t duration_sec, uint32_t duration_nsec, uint16_t idle_timeout, + uint64_t packet_count, uint64_t byte_count); + virtual ~FlowRemovedCommon() { + } + bool operator==(const FlowRemovedCommon &other) const; + bool operator!=(const FlowRemovedCommon &other) const; + uint64_t cookie() { + return this->cookie_; + } + uint16_t priority() { + return this->priority_; + } + uint8_t reason() { + return this->reason_; + } + uint32_t duration_sec() { + return this->duration_sec_; + } + uint32_t duration_nsec() { + return this->duration_nsec_; + } + uint64_t packet_count() { + return this->packet_count_; + } + uint64_t byte_count() { + return this->byte_count_; + } + void cookie(uint64_t cookie) { + this->cookie_ = cookie; + } + void priority(uint16_t priority) { + this->priority_ = priority; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } + void duration_sec(uint32_t duration_sec) { + this->duration_sec_ = duration_sec; + } + void duration_nsec(uint32_t duration_nsec) { + this->duration_nsec_ = duration_nsec; + } + void idle_timeout(uint16_t idle_timeout) { + this->idle_timeout_ = idle_timeout; + } + void packet_count(uint64_t packet_count) { + this->packet_count_ = packet_count; + } + void byte_count(uint64_t byte_count) { + this->byte_count_ = byte_count; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Port Status messages. + */ +class PortStatusCommon: public OFMsg { +protected: + uint8_t reason_; +public: + PortStatusCommon(uint8_t version, uint8_t type); + PortStatusCommon(uint8_t version, uint8_t type, uint32_t xid, + uint8_t reason); + virtual ~PortStatusCommon() { + } + bool operator==(const PortStatusCommon &other) const; + bool operator!=(const PortStatusCommon &other) const; + uint8_t reason() { + return this->reason_; + } + void reason(uint8_t reason) { + this->reason_ = reason; + } +}; + +/** + Base class for OpenFlow 1.0 and 1.3 Port Mod messages. + */ +class PortModCommon: public OFMsg { +protected: + EthAddress hw_addr_; + uint32_t config_; + uint32_t mask_; + uint32_t advertise_; +public: + PortModCommon(uint8_t version, uint8_t type); + PortModCommon(uint8_t version, uint8_t type, uint32_t xid, + EthAddress hw_addr, uint32_t config, uint32_t mask, uint32_t advertise); + virtual ~PortModCommon() { + } + bool operator==(const PortModCommon &other) const; + bool operator!=(const PortModCommon &other) const; + EthAddress hw_addr() { + return this->hw_addr_; + } + uint32_t config() { + return this->config_; + } + uint32_t mask() { + return this->mask_; + } + uint32_t advertise() { + return this->advertise_; + } + void hw_addr(EthAddress hw_addr) { + this->hw_addr_ = hw_addr; + } + void config(uint32_t config) { + this->config_ = config; + } + void mask(uint32_t mask) { + this->mask_ = mask; + } + void advertise(uint32_t advertise) { + this->advertise_ = advertise; + } +}; + +} //End of namespace fluid_msg +#endif + diff --git a/include/libfluid-msg/ofcommon/openflow-common.hh b/include/libfluid-msg/ofcommon/openflow-common.hh new file mode 100644 index 00000000..a8a773f8 --- /dev/null +++ b/include/libfluid-msg/ofcommon/openflow-common.hh @@ -0,0 +1,176 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 OPENFLOW_OPENFLOWCOMMON_H +#define OPENFLOW_OPENFLOWCOMMON_H 1 + +#ifdef __KERNEL__ +#include +#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 uint8_t OFP_ASSERT(EXPR) \ + 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 +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +namespace fluid_msg { + +/* Header on all OpenFlow packets. */ +struct ofp_fluid_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_fluid_header. */ + uint32_t xid; /* Transaction id associated with this packet. + Replies use the same id as was in the request + total_len facilitate pairing. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_header) == 8); + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_fluid_error_msg { + struct ofp_fluid_header header; + 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_fluid_error_msg) == 12); + +/* Switch configuration. */ +struct ofp_fluid_switch_config { + struct ofp_fluid_header header; + uint16_t flags; /* OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of new flow that datapath should + send to the controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_fluid_switch_config) == 12); + +/* 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); + +/* 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); + +const uint16_t DESC_FLUID_STR_LEN = 256; +const uint8_t SERIAL_FLUID_NUM_LEN = 32; + +/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated + * ASCII string. */ +struct ofp_desc { + char mfr_desc[DESC_FLUID_STR_LEN]; /* Manufacturer description. */ + char hw_desc[DESC_FLUID_STR_LEN]; /* Hardware description. */ + char sw_desc[DESC_FLUID_STR_LEN]; /* Software description. */ + char serial_num[SERIAL_FLUID_NUM_LEN]; /* Serial number. */ + char dp_desc[DESC_FLUID_STR_LEN]; /* Human readable description of datapath. */ +}; +OFP_ASSERT(sizeof(struct ofp_desc) == 1056); + +/* Role request and reply message. */ +struct ofp_role_request { + struct ofp_fluid_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_fluid_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); + +const uint8_t OFP_FLUID_MAX_TABLE_NAME_LEN = 32; +const uint8_t OFP_MAX_PORT_NAME_LEN = 16; +const uint16_t OFP_TCP_PORT = 6653; +const uint16_t OFP_SSL_PORT = 6653; +const uint8_t OFP_ETH_ALEN = 6; /* Bytes in an Ethernet address. */ +const uint8_t OFP_FLUID_DEFAULT_MISS_SEND_LEN = 128; +/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry + * is permanent. */ +const uint8_t OFP_FLUID_FLOW_PERMANENT = 0; +/* By default, choose a priority in the middle. */ +const uint16_t OFP_FLUID_DEFAULT_PRIORITY = 0x8000; +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +const uint32_t OFPQ_FLUID_ALL = 0xffffffff; +/* Min rate > 1000 means not configured. */ +const uint16_t OFPQ_MIN_RATE_UNCFG = 0xffff; + +typedef uint32_t of_error; + +const uint32_t OF_ERROR = 0xffffffff; + +/* Creates an of_error from an OpenFlow error type and code */ +static inline of_error openflow_error(uint16_t type, uint16_t code) { + /* NOTE: highest bit is always set to one, so no error value is zero */ + uint32_t ret = type; + return 0x80000000 | ret << 16 | code; +} + +/* Returns the error type of an of_error */ +static inline uint16_t of_error_type(of_error error) { + return (0x7fff0000 & error) >> 16; +} + +/* Returns the error code of an of_error */ +static inline uint16_t of_error_code(of_error error) { + return error & 0x0000ffff; +} + +typedef uint32_t of_err; + +} //End of namespace fluid_msg + +#endif diff --git a/include/libfluid-msg/util/ethaddr.hh b/include/libfluid-msg/util/ethaddr.hh new file mode 100644 index 00000000..0080fc52 --- /dev/null +++ b/include/libfluid-msg/util/ethaddr.hh @@ -0,0 +1,52 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 __MACADDRESS_H__ +#define __MACADDRESS_H__ + +#include +#include +#include + +#include +#include +#include + +namespace fluid_msg{ + +class EthAddress { + public: + EthAddress(); + EthAddress(const char* address); + EthAddress(const std::string &address); + EthAddress(const EthAddress &other); + EthAddress(const uint8_t* data); + + EthAddress& operator=(const EthAddress &other); + bool operator==(const EthAddress &other) const; + std::string to_string() const; + void set_data(uint8_t* array); + uint8_t* get_data(){return this->data;} + static uint8_t* data_from_string(const std::string &address); + + private: + uint8_t data[6]; + // void data_from_string(const std::string &address); +}; +} +#endif /* __MACADDRESS_H__ */ + + + diff --git a/include/libfluid-msg/util/ipaddr.hh b/include/libfluid-msg/util/ipaddr.hh new file mode 100644 index 00000000..df99407a --- /dev/null +++ b/include/libfluid-msg/util/ipaddr.hh @@ -0,0 +1,60 @@ +// Copyright (c) 2014 Open Networking Foundation +// Copyright 2020 Futurewei Cloud +// +// 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 __IPADDRESS_H__ +#define __IPADDRESS_H__ + +#include +#include +#include +#include +#include +#include + +namespace fluid_msg{ + +enum {NONE = 0, IPV4 = 4, IPV6 = 6 }; + +class IPAddress { + public: + IPAddress(); + IPAddress(const char* address); + IPAddress(const std::string &address); + IPAddress(const IPAddress &other); + IPAddress(const uint32_t ip_addr); + IPAddress(const uint8_t ip_addr[16]); + IPAddress(const struct in_addr& ip_addr); + IPAddress(const struct in6_addr& ip_addr); + ~IPAddress(){}; + + IPAddress& operator=(const IPAddress& other); + bool operator==(const IPAddress& other) const; + int get_version() const; + void setIPv4(uint32_t address); + void setIPv6(uint8_t address[16]); + uint32_t getIPv4(); + uint8_t * getIPv6(); + static uint32_t IPv4from_string(const std::string &address); + static struct in6_addr IPv6from_string(const std::string &address); + + private: + int version; + union { + uint32_t ipv4; + uint8_t ipv6[16]; + }; +}; +} +#endif /* __IPADDRESS_H__ */ diff --git a/include/libfluid-msg/util/util.h b/include/libfluid-msg/util/util.h new file mode 100644 index 00000000..f435eba9 --- /dev/null +++ b/include/libfluid-msg/util/util.h @@ -0,0 +1,170 @@ +/* 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 UTIL_H +#define UTIL_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(dst, src) ((dst) = (src)) +#endif +#endif + + +#ifndef __cplusplus +/* Build-time assertion for use in a statement context. */ +#define BUILD_ASSERT(EXPR) \ + sizeof(struct { unsigned int build_assert_failed : (EXPR) ? 1 : -1; }) + +/* Build-time assertion for use in a declaration context. */ +#define BUILD_ASSERT_DECL(EXPR) \ + extern int (*build_assert(void))[BUILD_ASSERT(EXPR)] +#else /* __cplusplus */ +#endif /* __cplusplus */ + +#define NO_RETURN __attribute__((__noreturn__)) +#define UNUSED __attribute__((__unused__)) +#define PACKED __attribute__((__packed__)) +//#define PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1))) +#define STRFTIME_FORMAT(FMT) __attribute__((__format__(__strftime__, FMT, 0))) +#define MALLOC_LIKE __attribute__((__malloc__)) +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +#define ARRAY_SIZE(ARRAY) (sizeof ARRAY / sizeof *ARRAY) +#define ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y) * (Y)) +#define ROUND_DOWN(X, Y) ((X) / (Y) * (Y)) +#define IS_POW2(X) ((X) && !((X) & ((X) - 1))) + +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif + +#define NOT_REACHED() abort() +#define NOT_IMPLEMENTED() abort() +#define NOT_TESTED() ((void) 0) /* XXX should print a message. */ + +/* Given POINTER, the address of the given MEMBER in a STRUCT object, returns + the STRUCT object. */ +#define CONTAINER_OF(POINTER, STRUCT, MEMBER) \ + ((STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER))) + +/* Check endianness on OS X. */ +#ifndef __BYTE_ORDER +#define __BYTE_ORDER __BYTE_ORDER__ +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static inline uint16_t +hton16(uint16_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return htons(n); +#endif +} + +static inline uint16_t +ntoh16(uint16_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return ntohs(n); +#endif +} + +static inline uint32_t +hton32(uint32_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return htonl(n); +#endif +} + +static inline uint32_t +ntoh32(uint32_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return ntohl(n); +#endif +} + +static inline uint64_t +hton64(uint64_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return (((uint64_t)hton32(n)) << 32) + hton32(n >> 32); +#endif +} + +static inline uint64_t +ntoh64(uint64_t n) { +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#else + return (((uint64_t)ntoh32(n)) << 32) + ntoh32(n >> 32); +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* util.h */ diff --git a/include/of_controller.h b/include/of_controller.h new file mode 100644 index 00000000..21147d70 --- /dev/null +++ b/include/of_controller.h @@ -0,0 +1,109 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#pragma once + +#include "of_message.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP + +#include "libfluid-base/OFServer.hh" +#include "libfluid-msg/of10msg.hh" +#include "libfluid-msg/of13msg.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fluid_base; +using namespace fluid_msg; + +class OFController : public OFServer { +public: + OFController(const std::unordered_map switch_dpid_map, + const std::unordered_map port_id_map, + const char* address = "0.0.0.0", + const int port = 1234, + const int nthreads = 4, + bool secure = false) : + xid(0), + switch_dpid_map(switch_dpid_map), + port_id_map(port_id_map), + OFServer(address, port, nthreads, secure, + OFServerSettings().supported_version(4) // OF version 0x04 is OF 1.3 + .echo_interval(30)) { } + + ~OFController() = default; + + void stop() override; + + void message_callback(OFConnection* ofconn, uint8_t type, void* data, size_t len) override; + + void connection_callback(OFConnection* ofconn, OFConnection::Event type) override; + + OFConnection* get_instance(std::string bridge); + + void add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn); + + void remove_switch_from_conn_map(std::string bridge); + + void remove_switch_from_conn_map(int ofconn_id); + + void setup_default_br_int_flows(); + + void setup_default_br_tun_flows(); + + void execute_flow(const std::string br, const std::string flow_str, const std::string action = "add"); + + void packet_out(const char* br, const char* opt); + +private: + // tracking xid (ovs transaction id) + std::atomic xid; + + // k is bridge name like 'br-int', v is OFConnection* obj + std::unordered_map switch_conn_map; + + // k is ofconnection id like '0', v is bridge name associated with it + std::unordered_map switch_id_map; + + // k is dpid (query from ovs), v is bridge name associated with it + std::unordered_map switch_dpid_map; + + // k is port name like (patch-int/tun and vxlan-generic), v is ofport id of it from ovsdb + std::unordered_map port_id_map; + + std::mutex switch_map_mutex; + + void send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p); + + void send_packet_out(OFConnection *ofconn, ofbuf_ptr_t &&po); + + void send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods); +}; diff --git a/include/of_message.h b/include/of_message.h new file mode 100644 index 00000000..583e3bca --- /dev/null +++ b/include/of_message.h @@ -0,0 +1,95 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#pragma once +#include +#include +#include +#include +#include + +class OFRawBuf { +public: + virtual ~OFRawBuf() = default; + virtual void* data() = 0; + virtual size_t len() = 0; +}; + +class OFMessage { +public: + virtual ~OFMessage() = default; + // xid + virtual uint32_t xid() = 0; + virtual void set_xid(uint32_t id) = 0; + // pack + virtual std::shared_ptr pack() = 0; +}; + +typedef uint32_t ofmsg_xid_t; +typedef std::shared_ptr ofmsg_ptr_t; +typedef std::shared_ptr ofbuf_ptr_t; + +class BundleFlowModMessage { +public: + BundleFlowModMessage(const std::vector flow_mods, std::atomic* fm_xid) : + _flow_mods(flow_mods), + _fm_xid(fm_xid) { } + + ~BundleFlowModMessage() = default; + + uint32_t get_bundle_id() { + return _bundle_id; + } + + std::shared_ptr pack_open_req(); + std::shared_ptr pack_commit_req(); + std::vector > pack_flow_mods(); + +private: + // bundle_id is generated from BundleCtrlMessage->pack() + uint32_t _bundle_id; + // starting x_id (auto increased for each message in this bundle, so all unique) + // need to sync auto increased value with caller for overall OF msg xid management + std::atomic* _fm_xid; + // each flow mod message may have different op_type, like bundling add/mod/delete flow operations together + std::vector _flow_mods; +}; + +class BundleReplyMessage { +public: + BundleReplyMessage() { } + + ~BundleReplyMessage() = default; + + uint32_t get_bundle_id() { + return _bundle_id; + } + + uint16_t get_type() { + return _type; + } + + void unpack(void* data); + +private: + uint32_t _bundle_id; + + uint16_t _type; +}; + +ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle = false); +ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict); +ofmsg_ptr_t create_del_flow(const std::string& match, bool strict); +std::vector create_add_flows(const std::vector& flows, bool bundle = false); +ofbuf_ptr_t create_packet_out(const char* option); \ No newline at end of file diff --git a/include/ovs_control.h b/include/ovs_control.h index fbdc75e7..c0694e1f 100644 --- a/include/ovs_control.h +++ b/include/ovs_control.h @@ -1,5 +1,5 @@ // Copyright (c) 2008-2017, 2019 Nicira, Inc. -// Copyright 2019 The Alcor Authors - file modified. +// Copyright 2020 Futurewei Cloud - file modified. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,144 +12,157 @@ // 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. - +#pragma once #ifndef OVS_CONTROL_H #define OVS_CONTROL_H #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define DSCP_DEFAULT (IPTOS_PREC_INTERNETCONTROL >> 2) -#define STDOUT_FILENO 1 /* Standard output. */ +#define STDOUT_FILENO 1 /* Standard output. */ #include /* add to /usr/local/include/openvswitch */ +#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include -extern "C" { - struct unixctl_conn; +extern "C" { +struct unixctl_conn; } + +// copy from ovs source code "include/openvswitch/ofp-table.h" +struct ofputil_table_map { + struct namemap map; +}; + +// copy from ovs source code "include/openvswitch/ofp-monitor.h" +char *parse_flow_monitor_request(struct ofputil_flow_monitor_request *, + const char *, const struct ofputil_port_map *, + const struct ofputil_table_map *, + enum ofputil_protocol *usable_protocols) OVS_WARN_UNUSED_RESULT; + // OVS implementation class namespace ovs_control { class OVS_Control { - public: - static OVS_Control &get_instance(); +public: + static OVS_Control &get_instance(); + + /* --names, --no-names: Show port and table names in output and accept them in + * input. (When neither is specified, the default is to accept port names but, + * for backward compatibility, not to show them unless this is an interactive + * console session.) */ + static int use_names; + static int verbosity; + static bool bundle; + /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ + static enum ofputil_protocol allowed_protocols; + /* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop" commands. */ + char *unixctl_path; + + /* + * structs and functions borrowed from ovs-ofctl.c + */ + void monitor(const char *bridge, const char *opt); + void packet_out(const char *bridge, const char *opt); + int dump_flows(const char *bridge, const char *flow, bool show_stats = true); + void dump_flows__(const char *bridge, const char *flow, bool aggregate); + int add_flow(const char *bridge, const char *flow); + int mod_flows(const char *bridge, const char *flow, bool strict); + int del_flows(const char *bridge, const char *flow, bool strict); + int flow_mod(const char *bridge, const char *flow, unsigned short int command); + void flow_mod__(const char *remote, struct ofputil_flow_mod *fms, + size_t n_fms, enum ofputil_protocol usable_protocols); + void bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, + size_t n_fms, enum ofputil_protocol usable_protocols); + vconn *prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, + ofputil_flow_stats_request *fsr, ofputil_protocol *protocolp); + enum ofputil_protocol + set_protocol_for_flow_dump(vconn *vconn, ofputil_protocol cur_protocol, + ofputil_protocol usable_protocols); + enum ofputil_protocol open_vconn_for_flow_mod(const char *remote, vconn **vconnp, + enum ofputil_protocol usable_protocols); + bool try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, + enum ofputil_protocol *cur); + void fetch_switch_config(vconn *vconn, ofputil_switch_config *config); + void set_switch_config(vconn *vconn, const ofputil_switch_config *config); + int open_vconn_socket(const char *name, vconn **vconnp); + void run(int retval, const char *message, ...); + enum ofputil_protocol open_vconn(const char *name, vconn **vconnp); + void bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, + const char *vconn_name); + void bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags); + void transact_noreply(vconn *vconn, ofpbuf *request); + void transact_multiple_noreply(vconn *vconn, ovs_list *requests); + int monitor_set_invalid_ttl_to_controller(vconn *vconn); + bool set_packet_in_format(vconn *vconn, enum nx_packet_in_format packet_in_format, + bool must_succeed); + void monitor_vconn(vconn *vconn, bool reply_to_echo_requests, + bool resume_continuations, const char *bridge); + void send_openflow_buffer(vconn *vconn, ofpbuf *buffer); + void dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge); -/* --names, --no-names: Show port and table names in output and accept them in - * input. (When neither is specified, the default is to accept port names but, - * for backward compatibility, not to show them unless this is an interactive - * console session.) */ - static int use_names; - static int verbosity; - static bool bundle; - /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ - static enum ofputil_protocol allowed_protocols; - /* --unixctl-path: Path to use for unixctl server, for "monitor" and "snoop" - commands. */ - char *unixctl_path; - - /* - * structs and funcntions borrow from ovs-ofctl.c - */ - void monitor(const char *bridge, const char *opt); - void packet_out(const char *bridge, const char *opt); - int dump_flows(const char *bridge, const char *flow, bool show_stats = true); - void dump_flows__(const char *bridge, const char *flow, bool aggregate); - int add_flow(const char *bridge, const char *flow); - int mod_flows(const char *bridge, const char *flow, bool strict); - int del_flows(const char *bridge, const char *flow, bool strict); - int flow_mod(const char *bridge, const char *flow, unsigned short int command); - void flow_mod__(const char *remote, struct ofputil_flow_mod *fms, - size_t n_fms, enum ofputil_protocol usable_protocols); - void bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, - size_t n_fms, enum ofputil_protocol usable_protocols); - vconn *prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, - ofputil_flow_stats_request *fsr, - ofputil_protocol *protocolp); - enum ofputil_protocol set_protocol_for_flow_dump(vconn *vconn, - ofputil_protocol cur_protocol, - ofputil_protocol usable_protocols); - enum ofputil_protocol open_vconn_for_flow_mod(const char *remote, vconn **vconnp, - enum ofputil_protocol usable_protocols); - bool try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, - enum ofputil_protocol *cur); - void fetch_switch_config(vconn *vconn, ofputil_switch_config *config); - void set_switch_config(vconn *vconn, const ofputil_switch_config *config); - int open_vconn_socket(const char *name, vconn **vconnp); - void run(int retval, const char *message, ...); - enum ofputil_protocol open_vconn(const char *name, vconn **vconnp); - void bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, - const char *vconn_name); - void bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags); - void transact_noreply(vconn *vconn, ofpbuf *request); - void transact_multiple_noreply(vconn *vconn, ovs_list *requests); - int monitor_set_invalid_ttl_to_controller(vconn *vconn); - bool set_packet_in_format(vconn *vconn, - enum ofputil_packet_in_format packet_in_format, - bool must_succeed); - void monitor_vconn(vconn *vconn, bool reply_to_echo_requests, - bool resume_continuations, const char *bridge); - void send_openflow_buffer(vconn *vconn, ofpbuf *buffer); - void dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge); - - struct barrier_aux { - struct vconn *vconn; /* OpenFlow connection for sending barrier. */ - struct unixctl_conn *conn; /* Connection waiting for barrier response. */ - }; + struct barrier_aux { + struct vconn *vconn; /* OpenFlow connection for sending barrier. */ + struct unixctl_conn *conn; /* Connection waiting for barrier response. */ + }; - enum PI { PI_FEATURES, PI_PORT_DESC }; - struct port_iterator { - struct vconn *vconn; - PI variant; - struct ofpbuf *reply; - ovs_be32 send_xid; - bool more; - }; - enum TI { TI_STATS, TI_FEATURES }; - struct table_iterator { - struct vconn *vconn; - TI variant; - struct ofpbuf *reply; - ovs_be32 send_xid; - bool more; + enum PI { PI_FEATURES, PI_PORT_DESC }; + struct port_iterator { + struct vconn *vconn; + PI variant; + struct ofpbuf *reply; + ovs_be32 send_xid; + bool more; + }; + enum TI { TI_STATS, TI_FEATURES }; + struct table_iterator { + struct vconn *vconn; + TI variant; + struct ofpbuf *reply; + ovs_be32 send_xid; + bool more; - struct ofputil_table_features features; - struct ofpbuf raw_properties; - }; + struct ofputil_table_features features; + struct ofpbuf raw_properties; + }; - ofp_port_t str_to_port_no(const char *vconn_name, const char *port_name); - bool str_to_ofp(const char *s, ofp_port_t *ofp_port); - void port_iterator_fetch_port_desc(port_iterator *pi); - void port_iterator_fetch_features(port_iterator *pi); - void port_iterator_init(port_iterator *pi, vconn *vconn); - bool port_iterator_next(port_iterator *pi, ofputil_phy_port *pp); - void port_iterator_destroy(port_iterator *pi); - void fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, ofputil_phy_port *pp); - const ofputil_port_map *get_port_map(const char *vconn_name); - const ofputil_port_map *ports_to_accept(const char *vconn_name); - const ofputil_port_map *ports_to_show(const char *vconn_name); - void table_iterator_init(table_iterator *ti, struct vconn *vconn); - const ofputil_table_features * table_iterator_next(table_iterator *ti); - void table_iterator_destroy(table_iterator *ti); - const ofputil_table_map *get_table_map(const char *vconn_name); - const ofputil_table_map *tables_to_accept(const char *vconn_name); - const ofputil_table_map *tables_to_show(const char *vconn_name); - bool should_accept_names(void); - bool should_show_names(void); - const char * openflow_from_hex(const char *hex, ofpbuf **msgp); + ofp_port_t str_to_port_no(const char *vconn_name, const char *port_name); + bool str_to_ofp(const char *s, ofp_port_t *ofp_port); + void port_iterator_fetch_port_desc(port_iterator *pi); + void port_iterator_fetch_features(port_iterator *pi); + void port_iterator_init(port_iterator *pi, vconn *vconn); + bool port_iterator_next(port_iterator *pi, ofputil_phy_port *pp); + void port_iterator_destroy(port_iterator *pi); + void fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, + ofputil_phy_port *pp); + const ofputil_port_map *get_port_map(const char *vconn_name); + const ofputil_port_map *ports_to_accept(const char *vconn_name); + const ofputil_port_map *ports_to_show(const char *vconn_name); + void table_iterator_init(table_iterator *ti, struct vconn *vconn); + const ofputil_table_features *table_iterator_next(table_iterator *ti); + void table_iterator_destroy(table_iterator *ti); + //const ofputil_table_map *get_table_map(const char *vconn_name); + //const ofputil_table_map *tables_to_accept(const char *vconn_name); + //const ofputil_table_map *tables_to_show(const char *vconn_name); + bool should_accept_names(void); + bool should_show_names(void); + const char *openflow_from_hex(const char *hex, ofpbuf **msgp); - // compiler will flag the error when below is called. - OVS_Control(OVS_Control const &) = delete; - void operator=(OVS_Control const &) = delete; + // compiler will flag the error when below is called. + OVS_Control(OVS_Control const &) = delete; + void operator=(OVS_Control const &) = delete; - private: - OVS_Control(){}; - ~OVS_Control(){}; +private: + OVS_Control(){}; + ~OVS_Control(){}; }; } // namespace ovs_control #endif // #ifndef OVS_CONTROL_H \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 485a950b..3accc472 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,21 +16,57 @@ set(SOURCES ./ovs/aca_vlan_manager.cpp ./ovs/ovs_control.cpp ./ovs/aca_ovs_control.cpp + ./ovs/aca_arp_responder.cpp + ./ovs/libfluid-base/base/BaseOFClient.cc + ./ovs/libfluid-base/base/BaseOFConnection.cc + ./ovs/libfluid-base/base/BaseOFServer.cc + ./ovs/libfluid-base/base/EventLoop.cc + ./ovs/libfluid-base/OFClient.cc + ./ovs/libfluid-base/OFConnection.cc + ./ovs/libfluid-base/OFServer.cc + ./ovs/libfluid-base/OFServerSettings.cc + ./ovs/libfluid-base/TLS.cc + ./ovs/libfluid-msg/of10/of10action.cc + ./ovs/libfluid-msg/of10/of10common.cc + ./ovs/libfluid-msg/of10/of10match.cc + ./ovs/libfluid-msg/of13/of13action.cc + ./ovs/libfluid-msg/of13/of13common.cc + ./ovs/libfluid-msg/of13/of13instruction.cc + ./ovs/libfluid-msg/of13/of13match.cc + ./ovs/libfluid-msg/of13/of13meter.cc + ./ovs/libfluid-msg/ofcommon/action.cc + ./ovs/libfluid-msg/ofcommon/common.cc + ./ovs/libfluid-msg/ofcommon/msg.cc + ./ovs/libfluid-msg/util/ethaddr.cc + ./ovs/libfluid-msg/util/ipaddr.cc + ./ovs/libfluid-msg/of10msg.cc + ./ovs/libfluid-msg/of13msg.cc + ./ovs/of_message.cpp + ./ovs/of_controller.cpp ./on_demand/aca_on_demand_engine.cpp ./dhcp/aca_dhcp_state_handler.cpp ./dhcp/aca_dhcp_server.cpp ./zeta/aca_zeta_oam_server.cpp - ./zeta/aca_zeta_programming.cpp - ./ovs/aca_arp_responder.cpp + ./zeta/aca_zeta_programming.cpp ) + +#Find libevent installation +find_path(LIBEVENT_INCLUDE_DIR + NAMES event2/thread.h + HINTS /usr/include + REQUIRED) + +FIND_LIBRARY(LIBUUID_LIBRARIES uuid) FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu NO_DEFAULT_PATH) FIND_LIBRARY(CPPKAFKA cppkafka /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(PULSAR pulsar /usr/lib NO_DEFAULT_PATH) -FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../include NO_DEFAULT_PATH) -link_libraries(${RDKAFKA} ${CPPKAFKA} ${OPENVSWITCH} ${PULSAR}) +link_libraries(${RDKAFKA} ${CPPKAFKA} ${PULSAR}) link_libraries(/usr/lib/x86_64-linux-gnu/libuuid.so) -include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${OPENVSWITCH_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR}) +link_libraries(/usr/lib/x86_64-linux-gnu/libevent_pthreads.so) +link_libraries(/usr/lib/x86_64-linux-gnu/libpthread.so) +link_libraries(/usr/local/lib/libopenvswitch.a) #this was installed by aca-machine-init.sh +include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/proto3) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/grpc) @@ -52,12 +88,15 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) add_library(AlcorControlAgentLib STATIC ${SOURCES}) +target_link_libraries(AlcorControlAgentLib event) #Libevent linking is '-levent', thus linked lib is 'event' in the cmd +target_link_libraries(AlcorControlAgentLib ssl) +target_link_libraries(AlcorControlAgentLib crypto) +target_link_libraries(AlcorControlAgentLib rt) add_executable(AlcorControlAgent aca_main.cpp) target_link_libraries(AlcorControlAgent cppkafka) target_link_libraries(AlcorControlAgent rdkafka) target_link_libraries(AlcorControlAgent pulsar) -target_link_libraries(AlcorControlAgent openvswitch) target_link_libraries(AlcorControlAgent AlcorControlAgentLib) target_link_libraries(AlcorControlAgent proto) target_link_libraries(AlcorControlAgent grpc) diff --git a/src/README.md b/src/README.md index 8833e6c8..2ce1abc8 100644 --- a/src/README.md +++ b/src/README.md @@ -69,15 +69,15 @@ You will need approval from at least one maintainer, who will merge your codes t ## Run the build script to set up the build container and compile the alcor-control-agent Assuming alcor-control-agent was cloned into ~/alcor-control-agent directory: ```Shell -cd ~/alcor-control-agent -./build/build.sh +cd ~/alcor-control-agent/build +sudo ./build.sh ``` ## You can also setup a physical machine or VM to compile the alcor-control-agent Assuming alcor-control-agent was cloned into ~/alcor-control-agent directory: ```Shell -cd ~/alcor-control-agent -./build/aca-machine-init.sh +cd ~/alcor-control-agent/build +sudo ./aca-machine-init.sh ``` ## Running alcor-control-agent and tests diff --git a/src/aca_main.cpp b/src/aca_main.cpp index f4c5330d..e599dc4a 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -14,14 +14,23 @@ #include "aca_log.h" #include "aca_util.h" -#include "aca_ovs_control.h" #include "aca_message_pulsar_consumer.h" #include "aca_grpc.h" #include "aca_grpc_client.h" + +#undef UNUSED +#include "of_controller.h" #include "aca_ovs_l2_programmer.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP #include "aca_ovs_control.h" + #include "goalstateprovisioner.grpc.pb.h" #include +#include #include /* for getopt */ #include #include @@ -45,8 +54,6 @@ using namespace std; // Global variables std::thread *g_grpc_server_thread = NULL; std::thread *g_grpc_client_thread = NULL; -std::thread *ovs_monitor_brtun_thread = NULL; -std::thread *ovs_monitor_brint_thread = NULL; GoalStateProvisionerAsyncServer *g_grpc_server = NULL; GoalStateProvisionerClientImpl *g_grpc_client = NULL; string g_broker_list = EMPTY_STRING; @@ -58,6 +65,8 @@ string g_ofctl_target = EMPTY_STRING; string g_ofctl_options = EMPTY_STRING; string g_ncm_address = EMPTY_STRING; string g_ncm_port = EMPTY_STRING; +string g_ovs_ctrl_address = "127.0.0.1"; +int g_ovs_ctrl_port = 1234; // total time for execute_system_command in microseconds std::atomic_ulong g_total_execute_system_time(0); @@ -111,7 +120,6 @@ static void aca_cleanup() // Stop sets a private variable running_ to False // The Dispatch checks the variable in a loop and stops when running is // no longer set to True. - if (g_grpc_server != NULL) { g_grpc_server->ShutDownServer(); delete g_grpc_server; @@ -129,7 +137,7 @@ static void aca_cleanup() ACA_LOG_ERROR("%s", "Unable to call delete, grpc server thread pointer is null.\n"); } - //stops the grpc client + // Stop the grpc client if (g_grpc_client != NULL) { delete g_grpc_client; g_grpc_client = NULL; @@ -145,6 +153,10 @@ static void aca_cleanup() } else { ACA_LOG_ERROR("%s", "Unable to call delete, grpc client thread pointer is null.\n"); } + + // Stop the ovs controller and clean up + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().clean_up_ovs_controller(); + ACA_LOG_CLOSE(); } @@ -206,7 +218,7 @@ int main(int argc, char *argv[]) case 'd': g_debug_mode = true; break; - default: /* the '?' case when the option is not recognized */ + default: //the '?' case when the option is not recognized fprintf(stderr, "Usage: %s\n" "\t\t[-a NCM IP Address]\n" @@ -249,7 +261,6 @@ int main(int argc, char *argv[]) g_grpc_server_thread->detach(); // Create a separate thread to run the grpc client. - g_grpc_client = new GoalStateProvisionerClientImpl(); g_grpc_client_thread = new std::thread( std::bind(&GoalStateProvisionerClientImpl::RunClient, g_grpc_client)); @@ -263,17 +274,24 @@ int main(int argc, char *argv[]) aca_cleanup(); return rc; } - // monitor br-int for dhcp request message - ovs_monitor_brint_thread = - new thread(bind(&ACA_OVS_Control::monitor, - &ACA_OVS_Control::get_instance(), "br-int", "resume")); - ovs_monitor_brint_thread->detach(); - // monitor br-tun for arp request message - ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); + // setup ovs controller with server ip address and port number, will be used for openflow operations + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().setup_ovs_controller(g_ovs_ctrl_address, g_ovs_ctrl_port); + + //// monitor br-int for dhcp request message + //ovs_monitor_brint_thread = + // new thread(bind(&ACA_OVS_Control::monitor, + // &ACA_OVS_Control::get_instance(), "br-int", "resume")); + //ovs_monitor_brint_thread->detach(); - ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); - rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + //// monitor br-tun for arp request message + //ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); + + //ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); + //rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + + pause(); aca_cleanup(); + return rc; } diff --git a/src/dhcp/aca_dhcp_server.cpp b/src/dhcp/aca_dhcp_server.cpp index 49bf09b1..06ec3f1e 100644 --- a/src/dhcp/aca_dhcp_server.cpp +++ b/src/dhcp/aca_dhcp_server.cpp @@ -20,9 +20,14 @@ #include #include #include -#include "aca_ovs_control.h" #include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace aca_dhcp_programming_if; @@ -63,24 +68,24 @@ void ACA_Dhcp_Server::_deinit_dhcp_db() void ACA_Dhcp_Server::_init_dhcp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; // adding dhcp default flows - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "add-flow br-int \"table=0,priority=25,udp,udp_src=68,udp_dst=67,actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-int", + "table=0,priority=25,udp,udp_src=68,udp_dst=67,actions=CONTROLLER", + "add"); return; } void ACA_Dhcp_Server::_deinit_dhcp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; // deleting dhcp default flows - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "del-flows br-int \"udp,udp_src=68,udp_dst=67\"", - not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-int", + "udp,udp_src=68,udp_dst=67", + "del"); return; } @@ -320,8 +325,10 @@ void ACA_Dhcp_Server::dhcps_xmit(uint32_t inport, void *message) //bridge = "br-int" opts = "in_port=controller packet= actions=normal" options = in_port + whitespace + packetpre + packet + whitespace + action; - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), - options.c_str()); + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), + // options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out(bridge.c_str(), + options.c_str()); delete dhcpmsg; } diff --git a/src/grpc/CMakeLists.txt b/src/grpc/CMakeLists.txt index 959b6b8f..aa9daeb2 100644 --- a/src/grpc/CMakeLists.txt +++ b/src/grpc/CMakeLists.txt @@ -17,7 +17,7 @@ set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure) set(_GRPC_CPP_PLUGIN_EXECUTABLE $) # Proto file -get_filename_component(aca_proto "../../alcor/schema/proto3/*.proto" ABSOLUTE) +get_filename_component(aca_proto "${CMAKE_CURRENT_SOURCE_DIR}/../../alcor/schema/proto3/*.proto" ABSOLUTE) get_filename_component(aca_proto_path "${aca_proto}" PATH) set(aca_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/goalstateprovisioner.pb.cc") @@ -37,4 +37,4 @@ add_custom_command( # Include generated *.pb.h files include_directories("${CMAKE_CURRENT_BINARY_DIR}") -ADD_LIBRARY(grpc ${aca_proto_srcs} ${aca_proto_hdrs} ${aca_grpc_srcs} ${aca_grpc_hdrs}) +ADD_LIBRARY(grpc ${aca_proto_srcs} ${aca_proto_hdrs} ${aca_grpc_srcs} ${aca_grpc_hdrs}) \ No newline at end of file diff --git a/src/net_config/aca_net_config.cpp b/src/net_config/aca_net_config.cpp index c4908b4f..45eabdec 100644 --- a/src/net_config/aca_net_config.cpp +++ b/src/net_config/aca_net_config.cpp @@ -16,6 +16,9 @@ #include "aca_util.h" #include "aca_config.h" #include "aca_net_config.h" + +#include +#include #include using namespace std; @@ -340,4 +343,32 @@ int Aca_Net_Config::execute_system_command(string cmd_string, ulong &culminative return rc; } +std::string Aca_Net_Config::execute_system_command_with_return(string cmd_string) +{ + char buffer[128]; + std::string result = ""; + + FILE* pipe = popen(cmd_string.c_str(), "r"); + if (!pipe) + { + ACA_LOG_ERROR("Aca_Net_Config::execute_system_command_with_return - failed to read output from popen\n"); + } + + try + { + while (fgets(buffer, sizeof buffer, pipe) != NULL) + { + result += buffer; + } + } + catch (...) + { + pclose(pipe); + ACA_LOG_ERROR("Aca_Net_Config::execute_system_command_with_return - failed to pclose cmd pipe\n"); + } + pclose(pipe); + + return result; +} + } // namespace aca_net_config diff --git a/src/on_demand/aca_on_demand_engine.cpp b/src/on_demand/aca_on_demand_engine.cpp index 804363e7..7c53e8ef 100644 --- a/src/on_demand/aca_on_demand_engine.cpp +++ b/src/on_demand/aca_on_demand_engine.cpp @@ -14,9 +14,7 @@ #include "aca_config.h" #include "aca_net_config.h" -#include "aca_on_demand_engine.h" #include "aca_vlan_manager.h" -#include "aca_ovs_control.h" #include "aca_grpc.h" #include "aca_grpc_client.h" #include "aca_log.h" @@ -35,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +40,12 @@ #include "goalstateprovisioner.pb.h" #include "aca_dhcp_server.h" #include "aca_arp_responder.h" +#include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_on_demand_engine.h" using namespace std; using namespace aca_vlan_manager; @@ -326,7 +329,9 @@ void ACA_On_Demand_Engine::on_demand(string uuid_for_call, OperationStatus statu ch++; } options = inport + whitespace + packetpre + serialized_packet + whitespace + action; - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out( + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out( + // bridge.c_str(), options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out( bridge.c_str(), options.c_str()); ACA_LOG_DEBUG("On-demand packet with protocol %d sent to ovs: %s\n", protocol, options.c_str()); diff --git a/src/ovs/aca_arp_responder.cpp b/src/ovs/aca_arp_responder.cpp index 8bb0b5c7..f2a2b4ae 100644 --- a/src/ovs/aca_arp_responder.cpp +++ b/src/ovs/aca_arp_responder.cpp @@ -62,10 +62,11 @@ void ACA_ARP_Responder::_init_arp_ofp() void ACA_ARP_Responder::_deinit_arp_ofp() { unsigned long not_care_culminative_time; - int overall_rc = EXIT_SUCCESS; - aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - "del-flows br-tun \"arp,arp_op=1\"", not_care_culminative_time, overall_rc); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(not_care_culminative_time, + "br-tun", + "arp,arp_op=1", + "del"); return; } @@ -257,8 +258,10 @@ void ACA_ARP_Responder::arp_xmit(uint32_t in_port, void *vlanmsg, void *message, } ACA_LOG_DEBUG("ACA_ARP_Responder sent arp packet to ovs: %s\n", options.c_str()); - aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), - options.c_str()); + //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), + // options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out(bridge.c_str(), + options.c_str()); } int ACA_ARP_Responder::_parse_arp_request(uint32_t in_port, vlan_message *vlanmsg, diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index 44a97758..f3d0ec01 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -210,38 +210,12 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() "-- set interface patch-int type=patch options:peer=patch-tun", not_care_culminative_time, overall_rc); - // adding default flows - // details at: https://github.com/futurewei-cloud/alcor-control-agent/wiki/Openflow-Tables-Explain - - execute_openflow_command("add-flow br-tun \"table=0,priority=50,arp,arp_op=1, actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=0,priority=1,in_port=\"patch-int\" actions=resubmit(,2)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=20,priority=1 actions=CONTROLLER\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=2,priority=25,icmp,icmp_type=8,in_port=\"patch-int\" actions=resubmit(,52)\"", - not_care_culminative_time, overall_rc); - - execute_openflow_command("add-flow br-tun \"table=52,priority=1 actions=resubmit(,20)\"", - not_care_culminative_time, overall_rc); - execute_ovsdb_command( string("--may-exist add-port br-tun vxlan-generic -- set interface vxlan-generic ofport_request=") + VXLAN_GENERIC_OUTPORT_NUMBER + " type=vxlan options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:remote_ip=flow", not_care_culminative_time, overall_rc); - execute_openflow_command("add-flow br-tun \"table=0,priority=25,in_port=\"vxlan-generic\" actions=resubmit(,4)\"", - not_care_culminative_time, overall_rc); setup_ovs_bridges_mutex.unlock(); // -----critical section ends----- @@ -274,6 +248,147 @@ int ACA_OVS_L2_Programmer::setup_ovs_bridges_if_need() return overall_rc; } +int ACA_OVS_L2_Programmer::setup_ovs_controller(const std::string ctrler_ip, const int ctrler_port) +{ + int rc = EXIT_SUCCESS; + + const string ctrler_endpoint = " tcp:" + ctrler_ip + ":" + to_string(ctrler_port); + const string br_int_str = "br-int"; + const string br_tun_str = "br-tun"; + const string setup_br_int_cmd = "set-controller " + br_int_str + ctrler_endpoint; + const string setup_br_tun_cmd = "set-controller " + br_tun_str + ctrler_endpoint; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::setup_ovs_controller ---> Entering\n"); + + // get bridge and dpid mappings from ovs + std::unordered_map switch_dpid_map = get_ovs_bridge_mapping(); + + // get system port name and ofportid mappings from ovs + std::unordered_map port_id_map = get_system_port_ids(); + + // set bridge controller will clean up flows + auto ovsdb_client_start = chrono::steady_clock::now(); + string br_int_cmd_string = "ovs-vsctl " + setup_br_int_cmd; + rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(br_int_cmd_string); + if (rc != EXIT_SUCCESS) { + ACA_LOG_ERROR("ACA_OVS_L2_Programmer::setup_ovs_controller - failed to set br-int controller\n"); + } + + string br_tun_cmd_string = "ovs-vsctl " + setup_br_tun_cmd; + rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(br_tun_cmd_string); + if (rc != EXIT_SUCCESS) { + ACA_LOG_ERROR("ACA_OVS_L2_Programmer::setup_ovs_controller - failed to set br-tun controller\n"); + } + + auto ovsdb_client_end = chrono::steady_clock::now(); + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::setup_ovs_controller - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + // start local ovs server (openflow controller) + ofctrl = new OFController(switch_dpid_map, port_id_map, ctrler_ip.c_str(), ctrler_port); + ofctrl->start(); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::setup_ovs_controller <--- Exiting\n"); + + return rc; +} + +void ACA_OVS_L2_Programmer::clean_up_ovs_controller() +{ + if (ofctrl != NULL) + { + ofctrl->stop(); + delete ofctrl; + ofctrl = NULL; + ACA_LOG_INFO("%s", "ACA_OVS_L2_Programmer::clean_up_ovs_controller - cleaned up ovs controller.\n"); + } + else + { + ACA_LOG_INFO("%s", "ACA_OVS_L2_Programmer::clean_up_ovs_controller - unable to clean up ovs controller, since it is null.\n"); + } +} + +std::string ACA_OVS_L2_Programmer::get_system_port_id(std::string port_name) +{ + return port_id_map[port_name]; +} + +std::unordered_map ACA_OVS_L2_Programmer::get_system_port_ids() +{ + // these 2 system ports belong to br-tun + const string patch_int_port = "patch-int"; + const string vxlan_generic_port = "vxlan-generic"; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::get_system_port_ids ---> Entering\n"); + auto ovsdb_client_start = chrono::steady_clock::now(); + + string patch_int_ofport_query = "ovs-vsctl get Interface " + patch_int_port + " ofport"; + string patch_int_ofport_id = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(patch_int_ofport_query); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids - adding %s - %s mapping to port_id_map\n", patch_int_port.c_str(), patch_int_ofport_id.c_str()); + port_id_map[patch_int_port] = patch_int_ofport_id; + + string vxlan_ofport_query = "ovs-vsctl get Interface " + vxlan_generic_port + " ofport"; + string vxlan_ofport_id = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(vxlan_ofport_query); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids - adding %s - %s mapping to port_id_map\n", vxlan_generic_port.c_str(), vxlan_ofport_id.c_str()); + port_id_map[vxlan_generic_port] = vxlan_ofport_id; + + auto ovsdb_client_end = chrono::steady_clock::now(); + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::get_system_port_ids - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_system_port_ids <--- Exiting\n"); + + return port_id_map; +} + +std::unordered_map ACA_OVS_L2_Programmer::get_ovs_bridge_mapping() +{ + const string br_int_str = "br-int"; + const string br_tun_str = "br-tun"; + const string get_br_int_dpid = "get Bridge " + br_int_str + " datapath_id"; + const string get_br_tun_dpid = "get Bridge " + br_tun_str + " datapath_id"; + std::unordered_map switch_dpid_map; + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::get_ovs_bridge_mapping ---> Entering\n"); + auto ovsdb_client_start = chrono::steady_clock::now(); + + string br_int_cmd_string = "ovs-vsctl " + get_br_int_dpid; + // raw string output format is like a hex string "00003af45ed7aa45" + string br_int_dpid_raw = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(br_int_cmd_string); + // trim the (") symbol at the start and the end to get 00003af45ed7aa45, and then convert to decimal + uint64_t br_int_dpid = std::stoul(br_int_dpid_raw.substr(1, br_int_dpid_raw.length() - 3), nullptr, 16); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - adding %ld - %s mapping to switch_dpid_map\n", br_int_dpid, br_int_str.c_str()); + switch_dpid_map[br_int_dpid] = br_int_str; + + string br_tun_cmd_string = "ovs-vsctl " + get_br_tun_dpid; + string br_tun_dpid_raw = aca_net_config::Aca_Net_Config::get_instance().execute_system_command_with_return(br_tun_cmd_string); + uint64_t br_tun_dpid = std::stoul(br_tun_dpid_raw.substr(1, br_tun_dpid_raw.length() - 3), nullptr, 16); + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - adding %ld - %s mapping to switch_dpid_map\n", br_tun_dpid, br_tun_str.c_str()); + switch_dpid_map[br_tun_dpid] = br_tun_str; + + auto ovsdb_client_end = chrono::steady_clock::now(); + auto ovsdb_client_time_total_time = + cast_to_microseconds(ovsdb_client_end - ovsdb_client_start).count(); + + g_total_execute_ovsdb_time += ovsdb_client_time_total_time; + + ACA_LOG_INFO("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping - Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds\n", + ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time)); + + ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::get_ovs_bridge_mapping <--- Exiting\n"); + + return switch_dpid_map; +} + int ACA_OVS_L2_Programmer::create_port(const string vpc_id, const string port_name, const string virtual_ip, const string virtual_mac, uint tunnel_id, ulong &culminative_time) @@ -520,4 +635,57 @@ void ACA_OVS_L2_Programmer::execute_openflow_command(const std::string cmd_strin ACA_LOG_DEBUG("ACA_OVS_L2_Programmer::execute_openflow_command <--- Exiting, rc = %d\n", rc); } +void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, + const std::string bridge, + const std::string flow_string, + const std::string action) +{ + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Entering\n"); + auto openflow_client_start = chrono::steady_clock::now(); + + if (NULL != ofctrl) { + ofctrl->execute_flow(bridge, flow_string, action); + } else { + ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::execute_openflow didn't find OF controller\n"); + } + + auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + + culminative_time += openflow_client_time_total_time; + + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Exiting\n"); +} + +void ACA_OVS_L2_Programmer::packet_out(const char *bridge, const char *options) +{ + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Entering\n"); + auto openflow_client_start = chrono::steady_clock::now(); + + if (NULL != ofctrl) { + ofctrl->packet_out(bridge, options); + } else { + ACA_LOG_ERROR("%s", "ACA_OVS_L2_Programmer::packet_out didn't find OF controller\n"); + } + + auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); + + ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::packet_out ---> Exiting\n"); +} + } // namespace aca_ovs_l2_programmer diff --git a/src/ovs/aca_ovs_l3_programmer.cpp b/src/ovs/aca_ovs_l3_programmer.cpp index 14c1cc01..8912fa8e 100644 --- a/src/ovs/aca_ovs_l3_programmer.cpp +++ b/src/ovs/aca_ovs_l3_programmer.cpp @@ -238,24 +238,28 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ // Program ICMP responder: cmd_string = - "add-flow br-tun \"table=52,priority=50,icmp,dl_vlan=" + + "table=52,priority=50,icmp,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + found_gateway_ip + " actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:" + found_gateway_mac + ",move:NXM_OF_IP_SRC[]->NXM_OF_IP_DST[],mod_nw_src:" + found_gateway_ip + - ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port\""; + ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "add"); // Should be able to ping the gateway now // add essential rule to restore from neighbor host DVR mac to destination GW mac: // Note: all port from the same subnet on current host will share this rule - cmd_string = "add-flow br-int \"table=0,priority=25,dl_vlan=" + + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + ",dl_src=" + HOST_DVR_MAC_MATCH + - " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL\""; + " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "add"); for (int k = 0; k < current_subnet_routing_table.routing_rules_size(); k++) { auto current_routing_rule = current_subnet_routing_table.routing_rules(k); @@ -349,27 +353,29 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ if (current_fixed_ip.subnet_id() != current_subnet_routing_table.subnet_id()) { cmd_string = - "add-flow br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + current_routing_rule.destination() + ",dl_dst=" + found_gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + gw_mac + - ",mod_dl_dst:" + virtual_mac_address + ",output:IN_PORT\""; + ",mod_dl_dst:" + virtual_mac_address + ",output:IN_PORT"; } } else { cmd_string = - "add-flow br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + current_routing_rule.destination() + ",dl_dst=" + found_gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + _host_dvr_mac + - ",mod_dl_dst:" + virtual_mac_address + ",resubmit(,2)\""; + ",mod_dl_dst:" + virtual_mac_address + ",resubmit(,2)"; } - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_dataplane_programming_time, + "br-tun", + cmd_string, + "add"); } } if (strcmp(remote_host_ip, "") != 0) { @@ -392,12 +398,14 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ int source_vlan_id = ACA_Vlan_Manager::get_instance().get_or_create_vlan_id(found_tunnel_id); string cmd_string = - "del-flows br-tun \"table=0,priority=50,ip,dl_vlan=" + + "table=0,priority=50,ip,dl_vlan=" + to_string(source_vlan_id) + ",dl_dst=" + found_gateway_mac + - ",nw_dst=" + current_routing_rule.destination() + "\" --strict"; + ",nw_dst=" + current_routing_rule.destination(); - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_dataplane_programming_time, + "br-tun", + cmd_string, + "del"); if (new_subnet_routing_table_entry.routing_rules.erase( current_routing_rule.id())) { ACA_LOG_INFO("Successfuly cleaned up entry for router rule id %s\n", @@ -549,20 +557,24 @@ int ACA_OVS_L3_Programmer::delete_router(RouterConfiguration ¤t_RouterConf stArpCfg.ipv4_address.c_str(), source_vlan_id); // Delete ICMP responder: - cmd_string = "del-flows br-tun \"table=52,icmp,dl_vlan=" + to_string(source_vlan_id) + - ",nw_dst=" + subnet_it->second.gateway_ip + "\""; + cmd_string = "table=52,icmp,dl_vlan=" + to_string(source_vlan_id) + + ",nw_dst=" + subnet_it->second.gateway_ip; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "del"); // remove essential rule which restore from neighbor host DVR mac to destination GW mac // Note: all port from the same subnet on current host will share this rule - cmd_string = "del-flows br-int \"table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + - ",dl_src=" + HOST_DVR_MAC_MATCH + "\" --strict"; + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + + ",dl_src=" + HOST_DVR_MAC_MATCH; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "del"); } // -----critical section starts----- @@ -762,25 +774,29 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ // Program ICMP responder: cmd_string = - "add-flow br-tun \"table=52,priority=50,icmp,dl_vlan=" + + "table=52,priority=50,icmp,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + found_gateway_ip + " actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:" + found_gateway_mac + ",move:NXM_OF_IP_SRC[]->NXM_OF_IP_DST[],mod_nw_src:" + found_gateway_ip + - ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port\""; + ",load:0xff->NXM_NX_IP_TTL[],load:0->NXM_OF_ICMP_TYPE[],in_port"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-tun", + cmd_string, + "add"); // Should be able to ping the gateway now // add essential rule to restore from neighbor host DVR mac to destination GW mac: // Note: all port from the same subnet on current host will share this rule - cmd_string = "add-flow br-int \"table=0,priority=25,dl_vlan=" + + cmd_string = "table=0,priority=25,dl_vlan=" + to_string(source_vlan_id) + ",dl_src=" + HOST_DVR_MAC_MATCH + - " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL\""; + " actions=mod_dl_src:" + found_gateway_mac + " output:NORMAL"; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, dataplane_programming_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(dataplane_programming_time, + "br-int", + cmd_string, + "add"); for (int k = 0; k < current_subnet_routing_table.routing_rules_size(); k++) { auto current_routing_rule = current_subnet_routing_table.routing_rules(k); @@ -987,23 +1003,25 @@ int ACA_OVS_L3_Programmer::create_or_update_l3_neighbor( // the openflow rule depends on whether the hosting ip is on this compute host or not if (is_port_on_same_host) { - cmd_string = "add-flow br-tun \"table=0,priority=25,ip,dl_vlan=" + + cmd_string = "table=0,priority=25,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + ",dl_dst=" + subnet_it->second.gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + destination_gw_mac + - ",mod_dl_dst:" + virtual_mac + ",output:IN_PORT\""; + ",mod_dl_dst:" + virtual_mac + ",output:IN_PORT"; } else { - cmd_string = "add-flow br-tun \"table=0,priority=25,ip,dl_vlan=" + + cmd_string = "table=0,priority=25,ip,dl_vlan=" + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + ",dl_dst=" + subnet_it->second.gateway_mac + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + ",mod_dl_src:" + _host_dvr_mac + - ",mod_dl_dst:" + virtual_mac + ",resubmit(,2)\""; + ",mod_dl_dst:" + virtual_mac + ",resubmit(,2)"; } - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "add"); } // we found our interested router from _routers_table which has the destination subnet GW connected to it. // Since each subnet GW can only be connected to one router, therefore, there is no point to look at other @@ -1085,11 +1103,13 @@ int ACA_OVS_L3_Programmer::delete_l3_neighbor(const string neighbor_id, const st // for the first implementation with static routing rules (non on-demand) // go ahead to remove it - string cmd_string = "del-flows br-tun \"table=0,priority=50,ip,dl_vlan=" + - to_string(source_vlan_id) + ",nw_dst=" + virtual_ip + "\" --strict"; + string cmd_string = "table=0,priority=50,ip,dl_vlan=" + + to_string(source_vlan_id) + ",nw_dst=" + virtual_ip; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "del"); // once we have the on demand routing rule implemented, we will need remove any // on demand routing rule assoicated this deleted neighbor to stop the traffic diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index eb7a3b5e..99721f75 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -15,9 +15,15 @@ #include "aca_log.h" #include "aca_util.h" #include "aca_vlan_manager.h" -#include "aca_ovs_control.h" #include "aca_ovs_l2_programmer.h" #include "aca_arp_responder.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + #include #include #include @@ -117,13 +123,16 @@ int ACA_Vlan_Manager::create_ovs_port(string /*vpc_id*/, string ovs_port, // to stamp with internal vlan and deliver to br-int if (current_vpc_table_entry->ovs_ports.empty()) { int internal_vlan_id = current_vpc_table_entry->vlan_id; + string patch_int_port_id = ACA_OVS_L2_Programmer::get_instance().get_system_port_id("patch-int"); string cmd_string = - "add-flow br-tun \"table=4, priority=1,tun_id=" + to_string(tunnel_id) + - " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:\"patch-int\"\""; + "table=4, priority=1,tun_id=" + to_string(tunnel_id) + + " actions=mod_vlan_vid:" + to_string(internal_vlan_id) + ",output:" + patch_int_port_id; - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "add"); current_vpc_table_entry->ovs_ports.insert(ovs_port, nullptr); } @@ -154,11 +163,13 @@ int ACA_Vlan_Manager::delete_ovs_port(string /*vpc_id*/, string ovs_port, // also delete the rule assoicated with the VPC: // table 4 = incoming vxlan, allow incoming vxlan traffic matching tunnel_id // to stamp with internal vlan and deliver to br-int - string cmd_string = "del-flows br-tun \"table=4, priority=1,tun_id=" + - to_string(tunnel_id) + "\" --strict"; + string cmd_string = "table=4, priority=1,tun_id=" + + to_string(tunnel_id); - ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( - cmd_string, culminative_time, overall_rc); + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + cmd_string, + "del"); } } @@ -169,14 +180,11 @@ int ACA_Vlan_Manager::delete_ovs_port(string /*vpc_id*/, string ovs_port, int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, string remote_host_ip, uint tunnel_id, - ulong & /*culminative_time*/) + ulong & culminative_time) { ACA_LOG_DEBUG("%s", "ACA_Vlan_Manager::create_l2_neighbor ---> Entering\n"); - int overall_rc; - int internal_vlan_id = get_or_create_vlan_id(tunnel_id); - arp_config stArpCfg; // match internal vlan based on VPC and destination neighbor mac, @@ -188,26 +196,26 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, string action_string = ",actions=strip_vlan,load:" + to_string(tunnel_id) + "->NXM_NX_TUN_ID[],set_field:" + remote_host_ip + "->tun_dst,output:" + VXLAN_GENERIC_OUTPORT_NUMBER; - std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); - overall_rc = ACA_OVS_Control::get_instance().add_flow( - "br-tun", (match_string + action_string).c_str()); + std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + match_string + action_string, + "add"); std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); + auto message_total_operation_time = std::chrono::duration_cast(end - start).count(); ACA_LOG_DEBUG("[create_l2_neighbor] Start adding ovs rule at: [%ld], finished at: [%ld]\nElapsed time for adding ovs rule for l2 neighbor took: %ld microseconds or %ld milliseconds\n", start, end, message_total_operation_time, (message_total_operation_time / 1000)); - if (overall_rc != EXIT_SUCCESS) { - ACA_LOG_ERROR("%s", "Failed to add L2 neighbor rule\n"); - }; // create arp entry in arp responder for the l2 neighbor stArpCfg.mac_address = virtual_mac; stArpCfg.ipv4_address = virtual_ip; stArpCfg.vlan_id = internal_vlan_id; - ACA_ARP_Responder::get_instance().create_or_update_arp_entry(&stArpCfg); + overall_rc = ACA_ARP_Responder::get_instance().create_or_update_arp_entry(&stArpCfg); ACA_LOG_DEBUG("create_l2_neighbor arp entry with ip = %s, vlan id = %u and mac = %s\n", virtual_ip.c_str(), internal_vlan_id, virtual_mac.c_str()); diff --git a/src/ovs/libfluid-base/OFClient.cc b/src/ovs/libfluid-base/OFClient.cc new file mode 100644 index 00000000..085d34bf --- /dev/null +++ b/src/ovs/libfluid-base/OFClient.cc @@ -0,0 +1,66 @@ +#include +#include + +#include "libfluid-base/OFClient.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/OFConnection.hh" +#include "libfluid-base/OFServer.hh" +#include "libfluid-base/base/of.hh" + +namespace fluid_base { + +OFClient::OFClient( + const std::string& addr, + const bool domainsocket, + const int port, + const bool secure, + const struct OFServerSettings ofsc) : + BaseOFClient(addr, domainsocket, port, secure), + OFConnectionProcessor(this) {} + +OFClient::~OFClient() {} + +bool OFClient::start(bool block) { + return BaseOFClient::start(block); +} + +void OFClient::stop() { + if (conn) { + conn->close(); + } + // Stop BaseOFClient + BaseOFClient::stop(); +} + +void OFClient::set_config(OFServerSettings ofsc) { + OFConnectionProcessor::set_config(ofsc); +} + +void OFClient::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + OFConnectionProcessor::base_message_callback(c, data, len); +} + +void OFClient::free_data(void* data) { + BaseOFClient::free_data(data); +} + +void OFClient::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + OFConnectionProcessor::base_connection_callback(c, event_type); + if (event_type == BaseOFConnection::EVENT_CLOSED) { + // reconnect + if (!this->connect()) { + fprintf(stderr, "OFClient reconnect failed"); + } else { + fprintf(stderr, "OFClient reconnect success"); + } + } +} + +void OFClient::on_new_conn(OFConnection* cc) { + if (conn) { + conn->close(); + } + conn.reset(cc); +} +} // namespace fluid_base diff --git a/src/ovs/libfluid-base/OFConnection.cc b/src/ovs/libfluid-base/OFConnection.cc new file mode 100644 index 00000000..1239e441 --- /dev/null +++ b/src/ovs/libfluid-base/OFConnection.cc @@ -0,0 +1,86 @@ +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/OFConnection.hh" + +namespace fluid_base { + +OFConnection::OFConnection(BaseOFConnection* c, OFHandler* ofhandler) { + this->ofhandler = ofhandler; + this->conn = c; + this->conn->set_manager(this); + this->id = c->get_id(); + this->peer_address = c->get_peer_address(); + this->set_state(STATE_HANDSHAKE); + this->set_alive(true); + this->set_version(0); + this->application_data = NULL; +} + +int OFConnection::get_id() { + return this->id; +} + +std::string OFConnection::get_peer_address() { + return this->peer_address; +} + +bool OFConnection::is_alive() { + return this->alive; +} + +void OFConnection::set_alive(bool alive) { + this->alive = alive; +} + +uint8_t OFConnection::get_state() { + return state; +} + +void OFConnection::set_state(OFConnection::State state) { + this->state = state; +} + +uint8_t OFConnection::get_version() { + return this->version; +} + +void OFConnection::set_version(uint8_t version) { + this->version = version; +} + +OFHandler* OFConnection::get_ofhandler() { + return this->ofhandler; +} + +void OFConnection::send(void* data, size_t len) { + if (this->conn != NULL) + this->conn->send((uint8_t*) data, len); +} + +void OFConnection::add_timed_callback(void* (*cb)(void*), + int interval, + void* arg) { + if (this->conn != NULL) + this->conn->add_timed_callback(cb, interval, arg); +} + +void* OFConnection::get_application_data() { + return this->application_data; +} + +void OFConnection::set_application_data(void* data) { + this->application_data = data; +} + +void OFConnection::close() { + // Don't close twice + if (this->conn == NULL) + return; + + set_state(STATE_DOWN); + // Close the BaseOFConnection. This will trigger + // BaseOFHandler::base_connection_callback. Then BaseOFServer will take + // care of freeing it for us, so we can lose track of it. + this->conn->close(); + this->conn = NULL; +} +} diff --git a/src/ovs/libfluid-base/OFServer.cc b/src/ovs/libfluid-base/OFServer.cc new file mode 100644 index 00000000..f7c59702 --- /dev/null +++ b/src/ovs/libfluid-base/OFServer.cc @@ -0,0 +1,270 @@ +#include +#include + +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/OFConnection.hh" +#include "libfluid-base/OFServer.hh" +#include "libfluid-base/base/of.hh" + +namespace fluid_base { +OFConnectionProcessor::OFConnectionProcessor(OFHandler* h) : _handler(h) {} + +void OFConnectionProcessor::set_config(OFServerSettings ofsc) { + this->ofsc = ofsc; +} + +void OFConnectionProcessor::free_data(void* data) { + _handler->free_data(data); +} + +OFServer::OFServer( + const char* address, + const int port, + const int nthreads, + const bool secure, + const OFServerSettings ofsc) : + BaseOFServer(address, port, nthreads, secure),OFConnectionProcessor(this) { + pthread_mutex_init(&ofconnections_lock, NULL); + this->set_config(ofsc); +} + +OFServer::~OFServer() { + this->lock_ofconnections(); + while (!this->ofconnections.empty()) { + OFConnection* ofconn = this->ofconnections.begin()->second; + this->ofconnections.erase(this->ofconnections.begin()); + delete ofconn; + } + this->ofconnections.clear(); + this->unlock_ofconnections(); +} + +bool OFServer::start(bool block) { + return BaseOFServer::start(block); +} + +void OFServer::stop() { + // Close all connections + this->lock_ofconnections(); + for (std::map::iterator it = this->ofconnections.begin(); + it != this->ofconnections.end(); + it++) { + it->second->close(); + } + this->unlock_ofconnections(); + + // Stop BaseOFServer + BaseOFServer::stop(); +} + +OFConnection* OFServer::get_ofconnection(int id) { + this->lock_ofconnections(); + OFConnection* cc = ofconnections[id]; + this->unlock_ofconnections(); + return cc; +} + +void OFServer::set_config(OFServerSettings ofsc) { + this->ofsc = ofsc; + OFConnectionProcessor::set_config(ofsc); +} + +static uint32_t version_bitmap_from_version(uint8_t ofp_version) { + return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1; +} + +void OFServer::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + OFConnectionProcessor::base_message_callback(c, data, len); +} + +void OFConnectionProcessor::base_message_callback(BaseOFConnection* c, void* data, size_t len) { + uint8_t version = ((uint8_t*) data)[0]; + uint8_t type = ((uint8_t*) data)[1]; + OFConnection* cc = (OFConnection*) c->get_manager(); + + // We trust that the other end is using the negotiated protocol version + // after the handshake is done. Should we? + + // Should we only answer echo requests after a features reply? The + // specification isn't clear about that, so we answer whenever an echo + // request arrives. + + // Handle echo requests + if (type == OFPT_ECHO_REQUEST) { + // Just change the type and send back + ((uint8_t*) data)[1] = OFPT_ECHO_REPLY; + c->send(data, ntohs(((uint16_t*) data)[1])); + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle hello messages + if (ofsc.handshake() and type == OFPT_HELLO) { + + uint32_t client_supported_versions; + + if (ofsc.use_hello_elements() && + len > 8 && + ntohs(((uint16_t*) data)[4]) == OFPHET_VERSIONBITMAP && + ntohs(((uint16_t*) data)[5]) >= 8) { + client_supported_versions = ntohl(((uint32_t*) data)[3]); + } + else { + client_supported_versions = version_bitmap_from_version(version); + } + + if (*this->ofsc.supported_versions() & client_supported_versions) { + struct ofp_fluid_header msg; + //msg.version = ((uint8_t*) data)[0]; + msg.version = this->ofsc.max_supported_version(); + msg.type = OFPT_FEATURES_REQUEST; + msg.length = htons(8); + msg.xid = ((uint32_t*) data)[1]; + c->send(&msg, 8); + } + else { + struct ofp_fluid_error_msg msg; + msg.header.version = version; + msg.header.type = OFPT_ERROR; + msg.header.length = htons(12); + msg.header.xid = ((uint32_t*) data)[1]; + msg.type = htons(OFPET_HELLO_FAILED); + msg.code = htons(OFPHFC_INCOMPATIBLE); + cc->send(&msg, 12); + + cc->close(); + cc->set_state(OFConnection::STATE_FAILED); + _handler->connection_callback(cc, OFConnection::EVENT_FAILED_NEGOTIATION); + } + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle echo replies (by registering them) + if (ofsc.liveness_check() and type == OFPT_ECHO_REPLY) { + if (ntohl(((uint32_t*) data)[1]) == ECHO_XID) { + cc->set_alive(true); + } + + if (ofsc.dispatch_all_messages()) goto dispatch; else goto done; + } + + // Handle feature replies + if (ofsc.handshake() and type == OFPT_FEATURES_REPLY) { + cc->set_version(((uint8_t*) data)[0]); + cc->set_state(OFConnection::STATE_RUNNING); + if (ofsc.liveness_check()) + c->add_timed_callback(send_echo, ofsc.echo_interval() * 1000, cc); + _handler->connection_callback(cc, OFConnection::EVENT_ESTABLISHED); + + goto dispatch; + } + + goto dispatch; + + // Dispatch a message to the user callback and goto done + dispatch: + _handler->message_callback(cc, type, data, len); + if (this->ofsc.keep_data_ownership()) + this->free_data(data); + return; + + // Free the message (if necessary) and return + done: + this->free_data(data); + return; +} + +void OFServer::free_data(void* data) { + BaseOFServer::free_data(data); +} + +void OFServer::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + OFConnectionProcessor::base_connection_callback(c, event_type); +} +void OFConnectionProcessor::base_connection_callback(BaseOFConnection* c, BaseOFConnection::Event event_type) { + // If the connection was closed, destroy it + // (BaseOFServer::base_connection_callback will do it for us). + // There's no need to notify the user, since a BaseOFConnection::EVENT_DOWN + // event already means a BaseOFConnection::EVENT_CLOSED will happen and + // nothing should be expected from the connection anymore. + if (event_type == BaseOFConnection::EVENT_CLOSED) { + delete c; + // TODO: delete the OFConnection? Currently we keep track of all + // connections that have been started and their status. When a + // connection is closed, pretty much all of its data is freed already, + // so this isn't a big overhead, and so we keep the references to old + // connections for the user. + return; + } + + if (event_type == BaseOFConnection::EVENT_UP) { + if (ofsc.handshake()) { + int msglen = 8; + if (ofsc.use_hello_elements()) { + msglen = 16; + } + + uint8_t msg[msglen]; + + struct ofp_hello* hello = (struct ofp_hello*) &msg; + hello->header.version = this->ofsc.max_supported_version(); + hello->header.type = OFPT_HELLO; + hello->header.length = htons(msglen); + hello->header.xid = htonl(HELLO_XID); + + if (this->ofsc.max_supported_version() >= 4 && ofsc.use_hello_elements()) { + struct ofp_hello_elem_versionbitmap* elm = + (struct ofp_hello_elem_versionbitmap*) (&msg[8]); + elm->type = htons(OFPHET_VERSIONBITMAP); + elm->length = htons(8); + + uint32_t* bitmaps = (uint32_t*) (&msg[12]); + *bitmaps = htonl(*this->ofsc.supported_versions()); + } + + c->send(&msg, msglen); + } + + OFConnection* cc = new OFConnection(c, _handler); + on_new_conn(cc); + _handler->connection_callback(cc, OFConnection::EVENT_STARTED); + } + else if (event_type == BaseOFConnection::EVENT_DOWN) { + auto cc = static_cast(c->get_manager()); + _handler->connection_callback(cc, OFConnection::EVENT_CLOSED); + cc->close(); + } +} + +void OFServer::on_new_conn(OFConnection* cc) { + lock_ofconnections(); + ofconnections[cc->get_id()] = cc; + unlock_ofconnections(); +} + +/** This method will periodically send echo requests. */ +void* OFConnectionProcessor::send_echo(void* arg) { + OFConnection* cc = static_cast(arg); + + if (!cc->is_alive()) { + cc->close(); + cc->get_ofhandler()->connection_callback(cc, OFConnection::EVENT_DEAD); + return NULL; + } + + uint8_t msg[8]; + memset((void*) msg, 0, 8); + msg[0] = (uint8_t) cc->get_version(); + msg[1] = OFPT_ECHO_REQUEST; + ((uint16_t*) msg)[1] = htons(8); + ((uint32_t*) msg)[1] = htonl(ECHO_XID); + + cc->set_alive(false); + cc->send(msg, 8); + + return NULL; +} + +} diff --git a/src/ovs/libfluid-base/OFServerSettings.cc b/src/ovs/libfluid-base/OFServerSettings.cc new file mode 100644 index 00000000..0e6cbaff --- /dev/null +++ b/src/ovs/libfluid-base/OFServerSettings.cc @@ -0,0 +1,108 @@ +#include "libfluid-base/OFServerSettings.hh" + +namespace fluid_base { + +OFServerSettings::OFServerSettings() { + this->_supported_versions = 0; + this->add_version(1); + this->version_set_by_hand = false; + this->echo_interval(15); + this->liveness_check(true); + this->handshake(true); + this->dispatch_all_messages(false); + this->use_hello_elements(false); + this->keep_data_ownership(true); +} + +OFServerSettings& OFServerSettings::supported_version(const uint8_t version) { + // If the user sets the version by hand, then all supported versions must + // be explicitly declared. + if (not this->version_set_by_hand) { + this->version_set_by_hand = true; + this->_supported_versions = 0; + } + this->add_version(version); + return *this; +} + +void OFServerSettings::add_version(const uint8_t version) { + this->_supported_versions |= (1 << version); + + unsigned int x = 0; + this->_max_supported_version = 0; + for (x = (unsigned int) this->_supported_versions; + x > 0; + x = x >> 1, this->_max_supported_version++); + this->_max_supported_version--; +} + +uint32_t* OFServerSettings::supported_versions() { + // We return a pointer because an OFServerSettings object is supposed to + // be exclusively user by an OFServer instance which has a copy of it. + + // TODO: since this->_supported_versions is just an uint32_t, we can only + // support OpenFlow versions lower than 31. It might be a problem some day, + // so it would be nice to change the implementation to a proper uint32_t + // array. + return &this->_supported_versions; +} + +uint8_t OFServerSettings::max_supported_version() { + return this->_max_supported_version; +} + +OFServerSettings& OFServerSettings::echo_interval(const int ei) { + this->_echo_interval = ei; + return *this; +} + +int OFServerSettings::echo_interval() { + return this->_echo_interval; +} + +OFServerSettings& OFServerSettings::liveness_check(const bool liveness_check) { + this->_liveness_check = liveness_check; + return *this; +} + +bool OFServerSettings::liveness_check() { + return this->_liveness_check; +} + +OFServerSettings& OFServerSettings::handshake(const bool handshake) { + this->_handshake = handshake; + return *this; +} + +bool OFServerSettings::handshake() { + return this->_handshake; +} + +OFServerSettings& OFServerSettings::dispatch_all_messages(const bool dispatch_all_messages) { + this->_dispatch_all_messages = dispatch_all_messages; + return *this; +} + +bool OFServerSettings::dispatch_all_messages() { + return this->_dispatch_all_messages; +} + +bool OFServerSettings::use_hello_elements() { + return this->_use_hello_elements; +} + +OFServerSettings& OFServerSettings::use_hello_elements(const bool use_hello_elements) { + this->_use_hello_elements = use_hello_elements; + return *this; +} + +bool OFServerSettings::keep_data_ownership() { + return this->_keep_data_ownership; +} + +OFServerSettings& OFServerSettings::keep_data_ownership(const bool keep_data_ownership) { + this->_keep_data_ownership = keep_data_ownership; + return *this; +} + +} diff --git a/src/ovs/libfluid-base/TLS.cc b/src/ovs/libfluid-base/TLS.cc new file mode 100644 index 00000000..c4211536 --- /dev/null +++ b/src/ovs/libfluid-base/TLS.cc @@ -0,0 +1,99 @@ +#include "libfluid-base/base/config.h" + +#if defined(HAVE_TLS) + +#include +#include +#include +#include +#include +#include + +#include + +#include "libfluid-base/TLS.hh" + +namespace fluid_base { + +void* tls_obj = NULL; +pthread_mutex_t* ssl_locks; +int ssl_num_locks; + +static unsigned long get_thread_id_cb(void) { + return (unsigned long) pthread_self(); +} + +static void thread_lock_cb(int mode, int which, const char * f, int l) { + if (which < ssl_num_locks) { + if (mode & CRYPTO_LOCK) { + pthread_mutex_lock(&(ssl_locks[which])); + } else { + pthread_mutex_unlock(&(ssl_locks[which])); + } + } +} + +// TODO: make these function idempotent + +void libfluid_tls_init(const char* cert, const char* privkey, const char* trustedcert) { + int i; + SSL_CTX *server_ctx; + + tls_obj = NULL; + + ssl_num_locks = CRYPTO_num_locks(); + ssl_locks = (pthread_mutex_t*) malloc(ssl_num_locks * sizeof(pthread_mutex_t)); + if (ssl_locks == NULL) + return; + + for (i = 0; i < ssl_num_locks; i++) { + pthread_mutex_init(&(ssl_locks[i]), NULL); + } + + // TODO: change this to the CRYPTO_THREADID family of functions to aid + // portability. While this will work on Linux, it is deprecated and should + // be changed. + CRYPTO_set_id_callback(get_thread_id_cb); + CRYPTO_set_locking_callback(thread_lock_cb); + + /* Initialize OpenSSL */ + SSL_load_error_strings(); + SSL_library_init(); + + /* Stop if there's no entropy */ + if (!RAND_poll()) + return; + + server_ctx = SSL_CTX_new(SSLv23_server_method()); + + if (!SSL_CTX_load_verify_locations(server_ctx, trustedcert, NULL)) { + fprintf(stderr, "Error loading verification CA certificate.\n"); + return; + } + SSL_CTX_set_verify(server_ctx, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + + if (!SSL_CTX_use_certificate_chain_file(server_ctx, cert)) { + fprintf(stderr, "Error loading certificate.\n"); + return; + } + + if (!SSL_CTX_use_PrivateKey_file(server_ctx, privkey, SSL_FILETYPE_PEM)) { + fprintf(stderr, "Error loading private key.\n"); + return; + } + + tls_obj = server_ctx; +} + +void libfluid_tls_clear() { + // TODO: investigate how to free the memory (~84k) that is still reachable + // after this function runs. + if (tls_obj != NULL) { + SSL_CTX_free((SSL_CTX*) tls_obj); + } +} + +} + +#endif diff --git a/src/ovs/libfluid-base/base/BaseOFClient.cc b/src/ovs/libfluid-base/base/BaseOFClient.cc new file mode 100644 index 00000000..d29a68cf --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFClient.cc @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "libfluid-base/base/BaseOFClient.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/EventLoop.hh" +#include "libfluid-base/TLS.hh" + +#include +#include + +namespace fluid_base { +#define OVS_CONN_SELECT_TIMEOUT 20 + +static bool evthread_use_pthreads_called = false; + +class BaseOFClient::LibEventBaseOFClient { +private: + friend class BaseOFClient; + + static void conn_cb(evutil_socket_t fd, const std::string &peer_address, void *arg); + static void conn_error_cb(void *arg); +}; + +BaseOFClient::BaseOFClient(const std::string &addr, const bool d, const int p, const bool s) : + address(addr), + domainsocket(d), + port(p), + secure(s), + blocking(false), + evloop(nullptr), + evthread(0), + nconn(0), + m_implementation(nullptr) { + // Prepare libevent for threads + // This will leave a small, insignificant leak for us. + // See: http://archives.seul.org/libevent/users/Jul-2011/msg00028.html + if (!evthread_use_pthreads_called) { + evthread_use_pthreads(); + evthread_use_pthreads_called = true; + } + + // Ignore SIGPIPE so it becomes an EPIPE + signal(SIGPIPE, SIG_IGN); + + m_implementation = new BaseOFClient::LibEventBaseOFClient; + +#if defined(HAVE_TLS) + if (this->secure && tls_obj == NULL) { + fprintf(stderr, "To establish secure connections, call libfluid_tls_init first.\n"); + } +#endif +} + +BaseOFClient::~BaseOFClient() { + delete this->m_implementation; + delete this->evloop; +} + +bool BaseOFClient::start(bool block) { + this->blocking = block; + + this->evloop = new EventLoop(0); + + // connect to ovs-db server and assign it to the event loop + if (!this->connect()) { + return false; + } + if (this->secure) { + fprintf(stderr, "Secure "); + } + fprintf(stderr, "ovs client started (%s)\n", this->address.c_str()); + + // start a new thread for event loop + pthread_create(&evthread, NULL, EventLoop::thread_adapter, evloop); + + return true; +} + +void BaseOFClient::stop() { + // ask event loop to stop + if (evloop) { + evloop->stop(); + } + + // wait for event loop thread to finish + if (evthread > 0) { + pthread_join(evthread, NULL); + } +} + +bool BaseOFClient::connect() { + int status = 0; + evutil_socket_t fd; + + if (this->domainsocket) { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + } else { + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } + + if (fd < 0) { + fprintf(stderr, "Could not create socket to %s\n", this->address.c_str()); + close(fd); + + return false; + } + + // if connect is non-blocking + if (!this->blocking) { + // set non-blocking mode socket flags + int flags = fcntl(fd, F_GETFL, 0); + int nonblocking_flags = flags | O_NONBLOCK; + + // set fd as non-blocking + fcntl(fd, F_SETFL, nonblocking_flags); + + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status == 0) { + // connect successfully immediately + fcntl(fd, F_SETFL, flags); + } else { + if (errno != EINPROGRESS) { + // if it did not connect immediately and errno != EINPROGRESS, it means there is + // error + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way, errno != " + "EINPROGRESS but = %d\n", + this->address.c_str(), + errno); + close(fd); + + return false; + } else { + fd_set read_fds; + fd_set write_fds; + struct timeval select_timeout; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_SET(fd, &read_fds); + FD_SET(fd, &write_fds); + + select_timeout.tv_sec = OVS_CONN_SELECT_TIMEOUT; + select_timeout.tv_usec = 0; + + status = ::select(fd + 1, &read_fds, &write_fds, NULL, &select_timeout); + + if (status <= 0) { + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way, select " + "timeout or error %d\n", + this->address.c_str(), + status); + close(fd); + + return false; + } + + if (FD_ISSET(fd, &write_fds)) { + if (FD_ISSET(fd, &read_fds)) { + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect( + fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect( + fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status != 0) { + int error = 0; + socklen_t len = sizeof(errno); + + // use getsockopt() to get fd error + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + fprintf(stderr, + "Could not get socket option of %s\n", + this->address.c_str()); + close(fd); + + return false; + } + + if (error != EISCONN) { + fprintf(stderr, + "Could not connect to %s and error != EISCONN\n", + this->address.c_str()); + close(fd); + + return false; + } + } + } + } else { + fprintf(stderr, + "Could not connect to openflow server %s in non-blocking way\n", + this->address.c_str()); + close(fd); + + return false; + } + + // connect successfully after select + fcntl(fd, F_SETFL, flags); + } + } + } else { + if (this->domainsocket) { + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, this->address.c_str(), sizeof(addr.sun_path) - 1); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + } else { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(this->address.c_str()); + addr.sin_port = htons(this->port); + status = ::connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + } + + if (status < 0) { + fprintf(stderr, + "Could not connect to openflow server %s, status is %d\n", + this->address.c_str(), + status); + close(fd); + + return false; + } + } + + // make the socket non-blocking + evutil_make_socket_nonblocking(fd); + + // create OvsdbConnection with connected socket fd and evloop + this->m_implementation->conn_cb(fd, address, this); + + return true; +} + +void BaseOFClient::free_data(void *data) { + BaseOFConnection::free_data(data); +} + +/* Internal libevent callbacks */ +void BaseOFClient::LibEventBaseOFClient::conn_cb( + evutil_socket_t fd, + const std::string &peer_address, + void *arg) { + auto client = static_cast(arg); + int id = client->nconn++; + + BaseOFConnection *c = + new BaseOFConnection(id, client, client->evloop, fd, client->secure, peer_address); +} + +void BaseOFClient::LibEventBaseOFClient::conn_error_cb(void *arg) { + int err = EVUTIL_SOCKET_ERROR(); + fprintf(stderr, + "BaseOFClient connection error (%d: %s)", + err, + evutil_socket_error_to_string(err)); +} + +} // namespace fluid_base diff --git a/src/ovs/libfluid-base/base/BaseOFConnection.cc b/src/ovs/libfluid-base/base/BaseOFConnection.cc new file mode 100644 index 00000000..de3b98fe --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFConnection.cc @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "libfluid-base/base/config.h" +#if defined(HAVE_TLS) +#include +#include +#include +#include +#include "libfluid-base/TLS.hh" +#endif + +#include "libfluid-base/base/BaseOFConnection.hh" + +namespace fluid_base { + +#define OF_HEADER_LENGTH 8 + +/** An OFReadBuffer holds an OpenFlow message while it is being read and built. + +This class is for internal use (it was created to simplify BaseOFConnection), +and it assumes the user will respect the read limits and will always inform +about read data. +*/ +class BaseOFConnection::OFReadBuffer { + public: + /** Create an BaseOFConnection::OFReadBuffer. */ + OFReadBuffer(){ + clear(); + } + ~OFReadBuffer() { + if (data != NULL) + delete[] data; + } + + /** Get how many bytes should be read for this buffer. + + If the buffer is initialized (a complete OpenFlow header has been + read), it will return how many bytes of the message are still unread. + + If the buffer is unitialized (a complete OpenFlow header has not been + read), it will return how many bytes of the header still need to be + read. + */ + inline uint16_t get_read_len() { + if (init) + return this->len - this->pos; + else + return OF_HEADER_LENGTH - header_pos; + } + + /** Get a pointer to the position at which a read operation should put + the data. + */ + inline uint8_t* get_read_pos() { + if (init) + return this->data + this->pos; + else + return this->header + this->header_pos; + } + + /** Notify the buffer that a read operation was made and a given number + of bytes is read. This will initialize the buffer for reading a message + if a complete OpenFlow header was read. + + @param read how many bytes were read + */ + inline void read_notify(uint16_t read) { + if (init) + this->pos += read; + else { + this->header_pos += read; + if (this->header_pos == OF_HEADER_LENGTH) { + this->len = htons(*((uint16_t*) this->header + 1)); + this->data = new uint8_t[this->len]; + memcpy(this->data, this->header, OF_HEADER_LENGTH); + this->pos += OF_HEADER_LENGTH; + init = true; + } + } + } + + /** Check if there is a complete OpenFlow message in the buffer. */ + inline bool is_ready(void) { + return (this->len != 0) && (this->pos == this->len); + } + + /** Fetch the data if there is a completely read OpenFlow message in + the buffer. Return NULL otherwise. */ + inline void* get_data(void) { + return this->data; + } + + /** Return the length of the message being read in this buffer (in + bytes). It will return 0 if the OpenFlow header has not been fully + received yet. */ + inline int get_len() { + return this->len; + } + + /** Clear the buffer, making it ready to read new messages. + + @param delete_data destroy the dinamically allocated data + (false by default) + */ + inline void clear(bool delete_data = false) { + if (delete_data and data != NULL) { + delete[] data; + } + this->data = NULL; + this->init = false; + + memset(this->header, 0, OF_HEADER_LENGTH); + this->header_pos = 0; + + this->pos = 0; + this->len = 0; + } + + /** Free a pointer allocated by this buffer. */ + static void free_data(void* data) { + delete[] (uint8_t*) data; + } + + uint8_t* data; + bool init; + + uint8_t header[OF_HEADER_LENGTH]; + uint16_t header_pos; + + uint16_t pos; + uint16_t len; +}; + +class BaseOFConnection::LibEventBaseOFConnection { +private: + friend class BaseOFConnection; + + struct bufferevent* bev{nullptr}; + struct event* close_event{nullptr}; + + static void event_cb(struct bufferevent *bev, short events, void* arg); + static void timer_callback(evutil_socket_t fd, short what, void *arg); + static void read_cb(struct bufferevent *bev, void* arg); + static void close_cb(int fd, short which, void *arg); +}; + +BaseOFConnection::BaseOFConnection(int id, + BaseOFHandler* ofhandler, + EventLoop* evloop, + int fd, + bool secure, + std::string peer_address) { + this->id = id; + this->peer_address = peer_address; + // TODO: move event_base to BaseOFConnection::LibEventBaseOFConnection so + // we don't need to store this here + this->evloop = evloop; + this->buffer = new BaseOFConnection::OFReadBuffer(); + this->manager = NULL; + this->ofhandler = ofhandler; + this->m_implementation = new BaseOFConnection::LibEventBaseOFConnection; + + struct event_base* base = (struct event_base*) evloop->get_base(); + this->m_implementation->close_event = event_new(base, + -1, + EV_PERSIST, + BaseOFConnection::LibEventBaseOFConnection::close_cb, + this); + event_add(this->m_implementation->close_event, NULL); + + this->secure = false; + #if defined(HAVE_TLS) + if (secure) { + if (tls_obj != NULL) { + SSL_CTX* server_ctx = (SSL_CTX*) tls_obj; + SSL* client_ctx = SSL_new(server_ctx); + this->m_implementation->bev = bufferevent_openssl_socket_new(base, + fd, client_ctx, + BUFFEREVENT_SSL_ACCEPTING, + BEV_OPT_CLOSE_ON_FREE | + BEV_OPT_THREADSAFE); + this->secure = true; + } + else { + fprintf(stderr, "Establishing insecure connection.\nYou must call libfluid_tls_init first to establish secure connections.\n"); + secure = false; + } + } + #endif + if (!this->m_implementation->bev) { + if (secure) { + fprintf(stderr, "Establishing insecure connection.\nYou intend to establish secure connection in environment of HAVE_TLS==0.\n"); + } + + this->m_implementation->bev = bufferevent_socket_new(base, + fd, + BEV_OPT_CLOSE_ON_FREE | + BEV_OPT_THREADSAFE); + } + + notify_conn_cb(BaseOFConnection::EVENT_UP); + + bufferevent_setcb(this->m_implementation->bev, + BaseOFConnection::LibEventBaseOFConnection::read_cb, + NULL, + BaseOFConnection::LibEventBaseOFConnection::event_cb, + this); + bufferevent_enable(this->m_implementation->bev, EV_READ|EV_WRITE); +} + +BaseOFConnection::~BaseOFConnection() { + delete this->m_implementation; +} + +void BaseOFConnection::send(void* data, size_t len) { + bufferevent_write(this->m_implementation->bev, data, len); +} + +void BaseOFConnection::add_timed_callback(void* (*cb)(void*), int interval, void* arg) { + struct timeval tv = { interval / 1000, (interval % 1000) * 1000 }; + struct timed_callback* tc = new struct timed_callback; + tc->cb = cb; + tc->cb_arg = arg; + struct event_base* base = (struct event_base*) this->evloop->get_base(); + struct event* ev = event_new(base, + -1, + EV_PERSIST, + BaseOFConnection::LibEventBaseOFConnection::timer_callback, + tc); + tc->data = ev; + timed_callbacks.push_back(tc); + event_add(ev, &tv); +} + +void BaseOFConnection::set_manager(void* manager) { + this->manager = manager; +} + +void* BaseOFConnection::get_manager() { + return this->manager; +} + +int BaseOFConnection::get_id() { + return this->id; +} + +std::string BaseOFConnection::get_peer_address() { + return this->peer_address; +} + +void BaseOFConnection::close() { + event_active(this->m_implementation->close_event, EV_READ, 0); +} + +void BaseOFConnection::free_data(void* data) { + BaseOFConnection::OFReadBuffer::free_data(data); +} + +/* Private BaseOFConnection methods */ +void BaseOFConnection::notify_msg_cb(void* data, size_t n) { + ofhandler->base_message_callback(this, data, n); +} + +void BaseOFConnection::notify_conn_cb(BaseOFConnection::Event event_type) { + ofhandler->base_connection_callback(this, event_type); +} + +void BaseOFConnection::do_close() { + // Stop all timed callbacks + struct timed_callback* tc; + for(std::vector::iterator it = timed_callbacks.begin(); + it != timed_callbacks.end(); + it++) { + tc = *it; + event_del((struct event*) tc->data); + event_free((struct event*) tc->data); + delete tc; + } + + // Stop the events and delete the buffers + event_del(this->m_implementation->close_event); + event_free(this->m_implementation->close_event); + + // Workaround for a clean SSL shutdown. + // See: http://www.wangafu.net/~nickm/libevent-book/Ref6a_advanced_bufferevents.html + #if defined(HAVE_TLS) + if (this->secure) { + SSL *ctx = bufferevent_openssl_get_ssl(this->m_implementation->bev); + SSL_set_shutdown(ctx, SSL_RECEIVED_SHUTDOWN); + SSL_shutdown(ctx); + } + #endif + + bufferevent_free(this->m_implementation->bev); + delete this->buffer; + this->buffer = NULL; + + notify_conn_cb(BaseOFConnection::EVENT_CLOSED); +} + +/* libevent callbacks */ +void BaseOFConnection::LibEventBaseOFConnection::event_cb(struct bufferevent *bev, short events, void* arg) { + BaseOFConnection* c = static_cast(arg); + + if (events & BEV_EVENT_ERROR) + perror("Connection error"); + if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { + bufferevent_disable(bev, EV_READ|EV_WRITE); + c->notify_conn_cb(BaseOFConnection::EVENT_DOWN); + } +} + +void BaseOFConnection::LibEventBaseOFConnection::timer_callback(evutil_socket_t fd, short what, void *arg) { + struct BaseOFConnection::timed_callback* tc = static_cast(arg); + tc->cb(tc->cb_arg); +} + +void BaseOFConnection::LibEventBaseOFConnection::read_cb(struct bufferevent *bev, void* arg) { + BaseOFConnection* c = static_cast(arg); + + uint16_t len; + BaseOFConnection::OFReadBuffer* ofbuf = c->buffer; + + while (1) { + // Decide how much we should read + len = ofbuf->get_read_len(); + if (len <= 0) break; + + // Read the data and put it in the buffer + size_t read = bufferevent_read(bev, ofbuf->get_read_pos(), len); + if (read <= 0) break; else ofbuf->read_notify(read); + + // Check if the message is fully received and dispatch + if (ofbuf->is_ready()) { + void* data = ofbuf->get_data(); + size_t len = ofbuf->get_len(); + ofbuf->clear(); + c->notify_msg_cb(data, len); + } + } +} + +void BaseOFConnection::LibEventBaseOFConnection::close_cb(int fd, short which, void *arg) { + BaseOFConnection* c = static_cast(arg); + c->do_close(); +} + +} diff --git a/src/ovs/libfluid-base/base/BaseOFServer.cc b/src/ovs/libfluid-base/base/BaseOFServer.cc new file mode 100644 index 00000000..69e1944a --- /dev/null +++ b/src/ovs/libfluid-base/base/BaseOFServer.cc @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "libfluid-base/base/BaseOFServer.hh" +#include "libfluid-base/base/BaseOFConnection.hh" +#include "libfluid-base/base/EventLoop.hh" +#include "libfluid-base/TLS.hh" + +#include +#include + +namespace fluid_base { + +static bool evthread_use_pthreads_called = false; + +class BaseOFServer::LibEventBaseOFServer { +private: + friend class BaseOFServer; + struct evconnlistener *listener; + static void conn_accept_cb(struct evconnlistener *listener, + evutil_socket_t fd, + struct sockaddr *address, + int socklen, + void *arg); + static void conn_accept_error_cb(struct evconnlistener *listener, + void* arg); +}; + +BaseOFServer::BaseOFServer(const char* address_, const int port, const int nthreads, bool secure) { + // Prepare libevent for threads + // This will leave a small, insignificant leak for us. + // See: http://archives.seul.org/libevent/users/Jul-2011/msg00028.html + if (!evthread_use_pthreads_called) { + evthread_use_pthreads(); + evthread_use_pthreads_called = true; + } + + // Ignore SIGPIPE so it becomes an EPIPE + signal(SIGPIPE, SIG_IGN); + + m_implementation = new BaseOFServer::LibEventBaseOFServer; + this->m_implementation->listener = NULL; + + this->nconn = 0; + + this->secure = secure; + + #if defined(HAVE_TLS) + if (this->secure && tls_obj == NULL) { + fprintf(stderr, "To establish secure connections, call libfluid_tls_init first.\n"); + } + #endif + + // Create event loops + // Threads will be created in BaseOFServer::start + this->nthreads = nthreads; + this->eventloops = new EventLoop*[nthreads]; + this->threads = new pthread_t[nthreads]; + memset(this->threads, 0, sizeof(pthread_t)*nthreads); + for (int i = 0; i < nthreads; i++) { + this->eventloops[i] = new EventLoop(i); + } + // The first event loop will be used for connections, so we move to the + // next one for the first connection + eventloop = 0; + if (nthreads > 1) + eventloop = 1; + + size_t address_len = strlen(address_) + 1; + this->address = new char[address_len]; + memcpy(this->address, address_, address_len); + snprintf(this->port, 6, "%d", port); +} + +BaseOFServer::~BaseOFServer() { + delete[] threads; + + if (this->m_implementation->listener != NULL) { + evconnlistener_free(this->m_implementation->listener); + this->m_implementation->listener = NULL; + } + + // Delete the event loops + for (int i = 0; i < nthreads; i++) { + delete eventloops[i]; + } + + delete[] eventloops; + + delete m_implementation; + + delete[] this->address; +} + +bool BaseOFServer::start(bool block) { + this->blocking = block; + + // Start listening for connections in the first event loop + if (not listen(eventloops[0])) + return false; + if (this->secure) + fprintf(stderr, "Secure "); + fprintf(stderr, "Server running (%s:%s)\n", this->address, this->port); + + // Start one thread for each event loop + // If we're blocking, the first event loop will run in the calling thread + for (int i = this->blocking? 1 : 0; i < nthreads; i++) { + pthread_create(&threads[i], + NULL, + EventLoop::thread_adapter, + eventloops[i]); + } + + // Start the first event loop in the calling thread if we're blocking + if (this->blocking) { + eventloops[0]->run(); + } + + return true; +} + +void BaseOFServer::stop() { + // Stop listening for new connections + if (m_implementation->listener != NULL) + evconnlistener_disable(m_implementation->listener); + + // Ask all event loops to stop + for (int i = 0; i < nthreads; i++) { + eventloops[i]->stop(); + } + + // Wait for all threads to finish (which will happen when the event loops + // stop running) + for (int i = this->blocking? 1 : 0; i < nthreads; i++) { + pthread_join(threads[i], NULL); + } +} + +bool BaseOFServer::listen(EventLoop* evloop) { + struct event_base *base = (struct event_base*) evloop->get_base();; + + // Hostname lookup + struct evutil_addrinfo hints; + struct evutil_addrinfo *result = NULL, *rp; + int err; + evutil_socket_t fd; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; + + err = evutil_getaddrinfo(this->address, this->port, &hints, &result); + if (err != 0) { + fprintf(stderr, "Error resolving '%s': %s\n", this->address, + evutil_gai_strerror(err)); + return false; + } + + int v = 1; + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); + if (fd == -1) + continue; + + if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) + break; + + close(fd); + } + + if (rp == NULL) { + fprintf(stderr, "Could not bind to '%s' (%s)\n", + this->address, strerror(errno)); + freeaddrinfo(result); + return false; + } + + freeaddrinfo(result); + + // Listen + evutil_make_socket_nonblocking(fd); + m_implementation->listener = evconnlistener_new(base, + m_implementation->conn_accept_cb, + this, + LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, + -1, + fd); + if (!m_implementation->listener) { + perror("Error creating connection listener"); + return false; + } + evconnlistener_set_error_cb(m_implementation->listener, m_implementation->conn_accept_error_cb); + + return true; +} + +EventLoop* BaseOFServer::choose_eventloop() { + EventLoop* selected_evloop = eventloops[eventloop]; + eventloop = (++eventloop) % nthreads; + return selected_evloop; +} + +void BaseOFServer::base_connection_callback(BaseOFConnection* conn, BaseOFConnection::Event event_type) { + if (event_type == BaseOFConnection::EVENT_CLOSED) + delete conn; +} + +void BaseOFServer::free_data(void* data) { + BaseOFConnection::free_data(data); +} + +static std::string get_in_addr(struct sockaddr *addr) +{ + const char* ret = NULL; + std::ostringstream sret; + + if (addr->sa_family == AF_INET) { + struct sockaddr_in* sa = (struct sockaddr_in*) addr; + + char peer[INET_ADDRSTRLEN]; + if (ret = evutil_inet_ntop(AF_INET, &sa->sin_addr, peer, sizeof(peer))) { + sret << ret << ':' << sa->sin_port; + } + } else if (addr->sa_family == AF_INET6) { + struct sockaddr_in6* sa = (struct sockaddr_in6*) addr; + + char peer[INET6_ADDRSTRLEN]; + if (ret = evutil_inet_ntop(AF_INET, &sa->sin6_addr, peer, sizeof(peer))) { + sret << '[' << ret << "]:" << sa->sin6_port; + } + } + + return sret.str(); +} + +/* Internal libevent callbacks */ +void BaseOFServer::LibEventBaseOFServer::conn_accept_cb(struct evconnlistener *listener, + evutil_socket_t fd, + struct sockaddr *address, + int socklen, + void *arg) { + + BaseOFServer* ofserver = static_cast(arg); + int id = ofserver->nconn++; + std::string saddr = get_in_addr(address); + BaseOFConnection* c = new BaseOFConnection(id, ofserver, ofserver->choose_eventloop(), fd, ofserver->secure, saddr); +} + +void BaseOFServer::LibEventBaseOFServer::conn_accept_error_cb(struct evconnlistener *listener, + void* arg) { + struct event_base *base = evconnlistener_get_base(listener); + int err = EVUTIL_SOCKET_ERROR(); + fprintf(stderr, "BaseOFServer error (%d :%s).", + err, evutil_socket_error_to_string(err)); +} + +} diff --git a/src/ovs/libfluid-base/base/EventLoop.cc b/src/ovs/libfluid-base/base/EventLoop.cc new file mode 100644 index 00000000..f676781d --- /dev/null +++ b/src/ovs/libfluid-base/base/EventLoop.cc @@ -0,0 +1,78 @@ +#include "libfluid-base/base/EventLoop.hh" +#include +#include + +namespace fluid_base { + +// Define our own value, since the stdint.h define doesn't work in C++ +#define OF_MAX_LEN 0xFFFF + +// See FIXME in EventLoop::EventLoop +//extern "C" void event_base_add_virtual(struct event_base *); +//extern "C" void event_base_del_virtual(struct event_base *); + +class EventLoop::LibEventEventLoop { +private: + friend class EventLoop; + struct event_base *base; +}; + +EventLoop::EventLoop(int id) { + this->id = id; + this->m_implementation = new EventLoop::LibEventEventLoop; + + this->m_implementation->base = event_base_new(); + + this->stopped = false; + if (!this->m_implementation->base) { + fprintf(stderr, "Error creating EventLoop %d\n", id); + exit(EXIT_FAILURE); + } + + /* FIXME: dirty hack warning! + We add a virtual event to prevent the loop from exiting when there are + no events. + + This fix is needed because libevent 2.0 doesn't have the flag + EVLOOP_NO_EXIT_ON_EMPTY. Version 2.1 fixes this, so this will have to + be changed in the future (to make it prettier and to avoid breaking + anything). + + See: + http://stackoverflow.com/questions/7645217/user-triggered-event-in-libevent + */ + //event_base_add_virtual(this->m_implementation->base); +} + +EventLoop::~EventLoop() { + event_base_free(this->m_implementation->base); + delete this->m_implementation; +} + +void EventLoop::run() { + // Only run if EventLoop::stop hasn't been called first + if (stopped) return; + + event_base_dispatch(this->m_implementation->base); + // See note in EventLoop::EventLoop. Here we disable the virtual event + // to guarantee that nothing blocks. + //event_base_del_virtual(this->m_implementation->base); + event_base_loop(this->m_implementation->base, EVLOOP_NO_EXIT_ON_EMPTY); +} + +void EventLoop::stop() { + // Prevent run from running if it's not started :) + this->stopped = true; + event_base_loopbreak(this->m_implementation->base); +} + +void* EventLoop::thread_adapter(void* arg) { + ((EventLoop*) arg)->run(); + return NULL; +} + +void* EventLoop::get_base() { + return this->m_implementation->base; +} + +} diff --git a/src/ovs/libfluid-msg/of10/of10action.cc b/src/ovs/libfluid-msg/of10/of10action.cc new file mode 100644 index 00000000..7ccee40d --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10action.cc @@ -0,0 +1,501 @@ +#include "libfluid-msg/of10/of10action.hh" +#include "libfluid-msg/of10/openflow-10.h" + +namespace fluid_msg { + +namespace of10 { + +OutputAction::OutputAction() + : Action(of10::OFPAT_OUTPUT, sizeof(struct of10::ofp_action_output)) { +} + +OutputAction::OutputAction(uint16_t port, uint16_t max_len) + : Action(of10::OFPAT_OUTPUT, sizeof(struct of10::ofp_action_output)) { + this->port_ = port; + this->max_len_ = max_len; +} + +bool OutputAction::equals(const Action &other) { + if (const OutputAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->max_len_ == act->max_len_)); + } + else { + return false; + } +} + +size_t OutputAction::pack(uint8_t *buffer) { + struct of10::ofp_action_output *oa = + (struct of10::ofp_action_output*) buffer; + Action::pack(buffer); + oa->port = hton16(this->port_); + oa->max_len = hton16(this->max_len_); + return 0; +} + +of_error OutputAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_output *oa = + (struct of10::ofp_action_output*) buffer; + Action::unpack(buffer); + this->port_ = ntoh16(oa->port); + this->max_len_ = ntoh16(oa->max_len); + return 0; +} + +SetVLANVIDAction::SetVLANVIDAction() + : Action(of10::OFPAT_SET_VLAN_VID, sizeof(struct of10::ofp_action_vlan_vid)) { +} + +SetVLANVIDAction::SetVLANVIDAction(uint16_t vlan_vid) + : Action(of10::OFPAT_SET_VLAN_VID, sizeof(struct of10::ofp_action_vlan_vid)) { + this->vlan_vid_ = vlan_vid; +} + +bool SetVLANVIDAction::equals(const Action &other) { + if (const SetVLANVIDAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vlan_vid_ == act->vlan_vid_)); + } + else { + return false; + } +} + +size_t SetVLANVIDAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vlan_vid *oa = + (struct of10::ofp_action_vlan_vid*) buffer; + Action::pack(buffer); + oa->vlan_vid = hton16(this->vlan_vid_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetVLANVIDAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vlan_vid *oa = + (struct of10::ofp_action_vlan_vid*) buffer; + Action::unpack(buffer); + this->vlan_vid_ = ntoh16(oa->vlan_vid); + return 0; +} + +SetVLANPCPAction::SetVLANPCPAction() + : Action(of10::OFPAT_SET_VLAN_PCP, sizeof(struct of10::ofp_action_vlan_pcp)) { +} + +SetVLANPCPAction::SetVLANPCPAction(uint8_t vlan_pcp) + : Action(of10::OFPAT_SET_VLAN_PCP, sizeof(struct of10::ofp_action_vlan_pcp)) { + this->vlan_pcp_ = vlan_pcp; +} + +bool SetVLANPCPAction::equals(const Action &other) { + if (const SetVLANPCPAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vlan_pcp_ == act->vlan_pcp_)); + } + else { + return false; + } +} + +size_t SetVLANPCPAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vlan_pcp *oa = + (struct of10::ofp_action_vlan_pcp*) buffer; + Action::pack(buffer); + oa->vlan_pcp = this->vlan_pcp_; + memset(oa->pad, 0x0, 3); + return 0; +} + +of_error SetVLANPCPAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vlan_pcp *oa = + (struct of10::ofp_action_vlan_pcp*) buffer; + Action::unpack(buffer); + this->vlan_pcp_ = oa->vlan_pcp; + return 0; +} + +StripVLANAction::StripVLANAction() + : Action(of10::OFPAT_STRIP_VLAN, sizeof(struct of10::ofp_action_header)) { +} + +size_t StripVLANAction::pack(uint8_t *buffer) { + return Action::pack(buffer); +} + +of_error StripVLANAction::unpack(uint8_t *buffer) { + return Action::unpack(buffer); +} + +SetDLSrcAction::SetDLSrcAction() + : Action(of10::OFPAT_SET_DL_SRC, sizeof(struct of10::ofp_action_dl_addr)) { +} + +SetDLSrcAction::SetDLSrcAction(EthAddress dl_addr) + : Action(of10::OFPAT_SET_DL_SRC, sizeof(struct of10::ofp_action_dl_addr)), + dl_addr_(dl_addr) { +} + +bool SetDLSrcAction::equals(const Action &other) { + if (const SetDLSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->dl_addr_ == act->dl_addr_)); + } + else { + return false; + } +} + +size_t SetDLSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::pack(buffer); + memcpy(oa->dl_addr, this->dl_addr_.get_data(), OFP_ETH_ALEN); + memset(oa->pad, 0x0, OFP_ETH_ALEN); + return 0; +} + +of_error SetDLSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::unpack(buffer); + this->dl_addr_ = EthAddress(oa->dl_addr); + return 0; +} + +SetDLDstAction::SetDLDstAction() + : Action(of10::OFPAT_SET_DL_DST, sizeof(struct of10::ofp_action_dl_addr)) { +} + +SetDLDstAction::SetDLDstAction(EthAddress dl_addr) + : Action(of10::OFPAT_SET_DL_DST, sizeof(struct of10::ofp_action_dl_addr)), + dl_addr_(dl_addr) { +} + +bool SetDLDstAction::equals(const Action &other) { + + if (const SetDLDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->dl_addr_ == act->dl_addr_)); + } + else { + return false; + } +} + +size_t SetDLDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::pack(buffer); + memcpy(oa->dl_addr, this->dl_addr_.get_data(), OFP_ETH_ALEN); + memset(oa->pad, 0x0, OFP_ETH_ALEN); + return 0; +} + +of_error SetDLDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_dl_addr *oa = + (struct of10::ofp_action_dl_addr*) buffer; + Action::unpack(buffer); + this->dl_addr_ = EthAddress(oa->dl_addr); + return 0; +} + +SetNWSrcAction::SetNWSrcAction() + : Action(of10::OFPAT_SET_NW_SRC, sizeof(struct of10::ofp_action_nw_addr)) { +} + +SetNWSrcAction::SetNWSrcAction(IPAddress nw_addr) + : Action(of10::OFPAT_SET_NW_SRC, sizeof(struct of10::ofp_action_nw_addr)), + nw_addr_(nw_addr) { +} + +bool SetNWSrcAction::equals(const Action &other) { + if (const SetNWSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_addr_ == act->nw_addr_)); + } + else { + return false; + } +} + +size_t SetNWSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::pack(buffer); + act->nw_addr = hton32(this->nw_addr_.getIPv4()); + return 0; +} + +of_error SetNWSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::unpack(buffer); + this->nw_addr_.setIPv4(ntoh32(act->nw_addr)); + return 0; +} + +SetNWDstAction::SetNWDstAction() + : Action(of10::OFPAT_SET_NW_DST, sizeof(struct of10::ofp_action_nw_addr)) { +} + +SetNWDstAction::SetNWDstAction(IPAddress nw_addr) + : Action(of10::OFPAT_SET_NW_DST, sizeof(struct of10::ofp_action_nw_addr)), + nw_addr_(nw_addr) { +} + +bool SetNWDstAction::equals(const Action &other) { + if (const SetNWDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_addr_ == act->nw_addr_)); + } + else { + return false; + } +} + +size_t SetNWDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::pack(buffer); + act->nw_addr = hton32(this->nw_addr_.getIPv4()); + return 0; +} + +of_error SetNWDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_addr *act = + (struct of10::ofp_action_nw_addr*) buffer; + Action::unpack(buffer); + this->nw_addr_.setIPv4(ntoh32(act->nw_addr)); + return 0; +} + +SetNWTOSAction::SetNWTOSAction() + : Action(of10::OFPAT_SET_NW_TOS, sizeof(struct of10::ofp_action_nw_tos)) { +} + +SetNWTOSAction::SetNWTOSAction(uint8_t nw_tos) + : Action(of10::OFPAT_SET_NW_TOS, sizeof(struct of10::ofp_action_nw_tos)) { + this->nw_tos_ = nw_tos; +} + +bool SetNWTOSAction::equals(const Action &other) { + if (const SetNWTOSAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_tos_ == act->nw_tos_)); + } + else { + return false; + } +} + +size_t SetNWTOSAction::pack(uint8_t *buffer) { + struct of10::ofp_action_nw_tos *oa = + (struct of10::ofp_action_nw_tos*) buffer; + Action::pack(buffer); + oa->nw_tos = this->nw_tos_; + memset(oa->pad, 0x0, 3); + return 0; +} + +of_error SetNWTOSAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_nw_tos *oa = + (struct of10::ofp_action_nw_tos*) buffer; + Action::unpack(buffer); + this->nw_tos_ = oa->nw_tos; + return 0; +} + +SetTPSrcAction::SetTPSrcAction() + : Action(of10::OFPAT_SET_TP_SRC, sizeof(struct of10::ofp_action_tp_port)) { +} + +SetTPSrcAction::SetTPSrcAction(uint16_t tp_port) + : Action(of10::OFPAT_SET_TP_SRC, sizeof(struct of10::ofp_action_tp_port)) { + this->tp_port_ = tp_port; +} + +bool SetTPSrcAction::equals(const Action &other) { + if (const SetTPSrcAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->tp_port_ == act->tp_port_)); + } + else { + return false; + } +} + +size_t SetTPSrcAction::pack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::pack(buffer); + oa->tp_port = hton16(this->tp_port_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetTPSrcAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::unpack(buffer); + this->tp_port_ = ntoh16(oa->tp_port); + return 0; +} + +SetTPDstAction::SetTPDstAction() + : Action(of10::OFPAT_SET_TP_DST, sizeof(struct of10::ofp_action_tp_port)) { +} + +SetTPDstAction::SetTPDstAction(uint16_t tp_port) + : Action(of10::OFPAT_SET_TP_DST, sizeof(struct of10::ofp_action_tp_port)) { + this->tp_port_ = tp_port; +} + +bool SetTPDstAction::equals(const Action &other) { + if (const SetTPDstAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->tp_port_ == act->tp_port_)); + } + else { + return false; + } +} + +size_t SetTPDstAction::pack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::pack(buffer); + oa->tp_port = hton16(this->tp_port_); + memset(oa->pad, 0x0, 2); + return 0; +} + +of_error SetTPDstAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_tp_port *oa = + (struct of10::ofp_action_tp_port*) buffer; + Action::unpack(buffer); + this->tp_port_ = ntoh16(oa->tp_port); + return 0; +} + +EnqueueAction::EnqueueAction() + : Action(of10::OFPAT_ENQUEUE, sizeof(struct of10::ofp_action_enqueue)) { +} + +EnqueueAction::EnqueueAction(uint16_t port, uint32_t queue_id) + : Action(of10::OFPAT_ENQUEUE, sizeof(struct of10::ofp_action_enqueue)) { + this->port_ = port; + this->queue_id_ = queue_id; +} + +bool EnqueueAction::equals(const Action &other) { + if (const EnqueueAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->queue_id_ == act->queue_id_)); + } + else { + return false; + } +} + +size_t EnqueueAction::pack(uint8_t *buffer) { + struct of10::ofp_action_enqueue *oa = + (struct of10::ofp_action_enqueue*) buffer; + Action::pack(buffer); + oa->port = hton16(this->port_); + memset(oa->pad, 0x0, 6); + oa->queue_id = hton32(this->queue_id_); + return 0; +} + +of_error EnqueueAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_enqueue *oa = + (struct of10::ofp_action_enqueue*) buffer; + Action::unpack(buffer); + this->port_ = ntoh16(oa->port); + this->queue_id_ = ntoh32(oa->queue_id); + return 0; +} + +VendorAction::VendorAction() + : Action(of10::OFPAT_VENDOR, sizeof(struct of10::ofp_action_vendor_header)) { +} + +VendorAction::VendorAction(uint32_t vendor) + : Action(of10::OFPAT_VENDOR, sizeof(struct of10::ofp_action_vendor_header)) { + this->vendor_ = vendor; +} + +bool VendorAction::equals(const Action &other) { + if (const VendorAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->vendor_ == act->vendor_)); + } + else { + return false; + } +} + +size_t VendorAction::pack(uint8_t *buffer) { + struct of10::ofp_action_vendor_header *oa = + (struct of10::ofp_action_vendor_header*) buffer; + Action::pack(buffer); + oa->vendor = hton32(this->vendor_); + return 0; +} + +of_error VendorAction::unpack(uint8_t *buffer) { + struct of10::ofp_action_vendor_header *oa = + (struct of10::ofp_action_vendor_header*) buffer; + Action::unpack(buffer); + this->vendor_ = ntoh32(oa->vendor); + return 0; +} + +} // End of namespace of10 + +Action * Action::make_of10_action(uint16_t type) { + switch (type) { + case (of10::OFPAT_OUTPUT): { + return new of10::OutputAction(); + } + case (of10::OFPAT_SET_VLAN_VID): { + return new of10::SetVLANVIDAction(); + } + case (of10::OFPAT_SET_VLAN_PCP): { + return new of10::SetVLANPCPAction(); + } + case (of10::OFPAT_STRIP_VLAN): { + return new of10::StripVLANAction(); + } + case (of10::OFPAT_SET_DL_SRC): { + return new of10::SetDLSrcAction(); + } + case (of10::OFPAT_SET_DL_DST): { + return new of10::SetDLDstAction(); + } + case (of10::OFPAT_SET_NW_SRC): { + return new of10::SetNWSrcAction(); + } + case (of10::OFPAT_SET_NW_DST): { + return new of10::SetNWDstAction(); + } + case (of10::OFPAT_SET_NW_TOS): { + return new of10::SetNWTOSAction(); + } + case (of10::OFPAT_SET_TP_SRC): { + return new of10::SetTPSrcAction(); + } + case (of10::OFPAT_SET_TP_DST): { + return new of10::SetTPDstAction(); + } + case (of10::OFPAT_ENQUEUE): { + return new of10::EnqueueAction(); + } + case (of10::OFPAT_VENDOR): { + return new of10::VendorAction(); + } + } + return NULL; +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10/of10common.cc b/src/ovs/libfluid-msg/of10/of10common.cc new file mode 100644 index 00000000..7a14422a --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10common.cc @@ -0,0 +1,333 @@ +#include "libfluid-msg/of10/of10common.hh" + +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +namespace of10 { + +Port::Port(uint16_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer) + : PortCommon(hw_addr, name, config, state, curr, advertised, supported, + peer) { + this->port_no_ = port_no; +} + +bool Port::operator==(const Port &other) const { + return (PortCommon::operator==(other) && (this->port_no_ == other.port_no_)); +} + +bool Port::operator!=(const Port &other) const { + return !(*this == other); +} + +size_t Port::pack(uint8_t* buffer) { + struct of10::ofp_phy_port *port = (struct of10::ofp_phy_port*) buffer; + port->port_no = hton16(this->port_no_); + memcpy(port->hw_addr, this->hw_addr_.get_data(), OFP_ETH_ALEN); + memset(port->name, 0x0, OFP_MAX_PORT_NAME_LEN); + memcpy(port->name, this->name_.c_str(), + this->name_.size() < OFP_MAX_PORT_NAME_LEN ? + this->name_.size() : OFP_MAX_PORT_NAME_LEN); + port->config = hton32(this->config_); + port->state = hton32(this->state_); + port->curr = hton32(this->curr_); + port->advertised = hton32(this->advertised_); + port->supported = hton32(this->supported_); + port->peer = hton32(this->peer_); + return 0; +} +of_error Port::unpack(uint8_t* buffer) { + struct of10::ofp_phy_port *port = (struct of10::ofp_phy_port*) buffer; + this->port_no_ = ntoh16(port->port_no); + this->hw_addr_ = EthAddress(port->hw_addr); + this->name_ = std::string(port->name); + this->config_ = ntoh32(port->config); + this->state_ = ntoh32(port->state); + this->curr_ = ntoh32(port->curr); + this->advertised_ = ntoh32(port->advertised); + this->supported_ = ntoh32(port->supported); + this->peer_ = ntoh32(port->peer); + return 0; +} + +QueuePropMinRate::QueuePropMinRate(uint16_t rate) + : QueuePropRate(of10::OFPQT_MIN_RATE, rate) { + this->len_ = sizeof(struct of10::ofp_queue_prop_min_rate); +} + +bool QueuePropMinRate::equals(const QueueProperty &other) { + if (const QueuePropMinRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMinRate::pack(uint8_t* buffer) { + struct of10::ofp_queue_prop_min_rate *qp = + (struct of10::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMinRate::unpack(uint8_t* buffer) { + struct of10::ofp_queue_prop_min_rate *qp = + (struct of10::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +PacketQueue::PacketQueue(uint32_t queue_id) + : PacketQueueCommon(queue_id) { + this->len_ = sizeof(struct of10::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, QueuePropertyList properties) + : PacketQueueCommon(queue_id) { + this->properties_ = properties; + this->len_ = sizeof(struct of10::ofp_packet_queue) + properties.length(); +} + +size_t PacketQueue::pack(uint8_t* buffer) { + struct of10::ofp_packet_queue *pq = (struct of10::ofp_packet_queue*) buffer; + pq->queue_id = hton32(this->queue_id_); + pq->len = hton16(this->len_); + memset(pq->pad, 0x0, 2); + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_queue); + this->properties_.pack(p); + return this->len_; +} + +of_error PacketQueue::unpack(uint8_t* buffer) { + struct of10::ofp_packet_queue *pq = (struct of10::ofp_packet_queue*) buffer; + this->queue_id_ = ntoh32(pq->queue_id); + this->len_ = ntoh16(pq->len); + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_queue); + this->properties_.length( + this->len_ - sizeof(struct of10::ofp_packet_queue)); + this->properties_.unpack10(p); + return 0; +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + + this->length_ = sizeof(struct of10::ofp_flow_stats); +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count, of10::Match match, ActionList actions) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + this->match_ = match; + this->actions_ = actions; + this->length_ = sizeof(struct of10::ofp_flow_stats) + actions.length(); +} + +bool FlowStats::operator==(const FlowStats &other) const { + return ((FlowStatsCommon::operator==(other)) + && (this->actions_ == other.actions_) && (this->match_ == other.match_)); +} + +bool FlowStats::operator!=(const FlowStats &other) const { + return !(*this == other); +} + +size_t FlowStats::pack(uint8_t* buffer) { + struct of10::ofp_flow_stats *fs = (struct of10::ofp_flow_stats*) buffer; + this->match_.pack(buffer + 4); + fs->length = hton16(this->length_); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->duration_sec = hton32(this->duration_sec_); + fs->duration_nsec = hton32(this->duration_nsec_); + fs->priority = hton16(this->priority_); + fs->idle_timeout = hton16(this->idle_timeout_); + fs->hard_timeout = hton16(this->hard_timeout_); + memset(fs->pad2, 0x0, 6); + fs->cookie = hton64(this->cookie_); + fs->packet_count = hton64(this->packet_count_); + fs->byte_count = hton64(this->byte_count_); + uint8_t *p = buffer + sizeof(struct of10::ofp_flow_stats); + this->actions_.pack(p); + return this->length_; +} + +of_error FlowStats::unpack(uint8_t* buffer) { + struct of10::ofp_flow_stats *fs = (struct of10::ofp_flow_stats*) buffer; + this->match_.unpack(buffer + 4); + this->length_ = ntoh16(fs->length); + this->table_id_ = fs->table_id; + this->duration_sec_ = ntoh32(fs->duration_sec); + this->duration_nsec_ = ntoh32(fs->duration_nsec); + this->priority_ = ntoh16(fs->priority); + this->idle_timeout_ = ntoh16(fs->idle_timeout); + this->hard_timeout_ = ntoh16(fs->hard_timeout); + this->cookie_ = ntoh64(fs->cookie); + this->packet_count_ = ntoh64(fs->packet_count); + this->byte_count_ = ntoh64(fs->byte_count); + this->actions_.length(this->length_ - sizeof(struct of10::ofp_flow_stats)); + uint8_t * p = buffer + sizeof(struct of10::ofp_flow_stats); + this->actions_.unpack10(p); + return 0; +} + +void FlowStats::actions(ActionList actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void FlowStats::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void FlowStats::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +TableStats::TableStats(uint8_t table_id, std::string name, uint32_t wildcards, + uint32_t max_entries, uint32_t active_count, uint64_t lookup_count, + uint64_t matched_count) + : TableStatsCommon(table_id, active_count, lookup_count, matched_count) { + this->name_ = name; + this->wildcards_ = wildcards; + this->max_entries_ = max_entries; +} + +bool TableStats::operator==(const TableStats &other) const { + return ((TableStatsCommon::operator==(other)) + && (this->name_ == other.name_) + && (this->wildcards_ == other.wildcards_) + && (this->max_entries_ == other.max_entries_)); +} + +bool TableStats::operator!=(const TableStats &other) const { + return !(*this == other); +} + +size_t TableStats::pack(uint8_t* buffer) { + struct of10::ofp_table_stats *ts = (struct of10::ofp_table_stats*) buffer; + ts->table_id = this->table_id_; + memset(ts->pad, 0x0, 3); + memset(ts->name, 0x0, OFP_FLUID_MAX_TABLE_NAME_LEN); + memcpy(ts->name, this->name_.c_str(), + this->name_.size() < OFP_FLUID_MAX_TABLE_NAME_LEN ? + this->name_.size() : OFP_FLUID_MAX_TABLE_NAME_LEN); + ts->wildcards = hton32(this->wildcards_); + ts->max_entries = hton32(this->max_entries_); + ts->active_count = hton32(this->active_count_); + ts->lookup_count = hton64(this->lookup_count_); + ts->matched_count = hton64(this->matched_count_); + return 0; +} + +of_error TableStats::unpack(uint8_t* buffer) { + struct of10::ofp_table_stats *ts = (struct of10::ofp_table_stats*) buffer; + this->table_id_ = ts->table_id; + this->name_ = std::string(ts->name); + this->wildcards_ = ntoh32(ts->wildcards); + this->max_entries_ = ntoh32(ts->max_entries); + this->active_count_ = ntoh32(ts->active_count); + this->lookup_count_ = ntoh64(ts->lookup_count); + this->matched_count_ = ntoh64(ts->matched_count); + return 0; +} + +PortStats::PortStats(uint16_t port_no, struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions) + : PortStatsCommon(rx_tx_stats, err_stats, collisions) { + this->port_no_ = port_no; +} + +bool PortStats::operator==(const PortStats &other) const { + return ((PortStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortStats::operator!=(const PortStats &other) const { + return !(*this == other); +} + +size_t PortStats::pack(uint8_t* buffer) { + struct of10::ofp_port_stats *ps = (struct of10::ofp_port_stats*) buffer; + ps->port_no = hton16(this->port_no_); + memset(ps->pad, 0x0, 6); + PortStatsCommon::pack(buffer + 8); + ps->collisions = hton64(this->collisions_); + return 0; +} + +of_error PortStats::unpack(uint8_t* buffer) { + struct of10::ofp_port_stats *ps = (struct of10::ofp_port_stats*) buffer; + this->port_no_ = ntoh16(ps->port_no); + PortStatsCommon::unpack(buffer + 8); + this->collisions_ = ntoh64(ps->collisions); + return 0; +} + +QueueStats::QueueStats(uint16_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors) + : QueueStatsCommon(queue_id, tx_bytes, tx_packets, tx_errors) { + this->port_no_ = port_no; +} + +bool QueueStats::operator==(const QueueStats &other) const { + return ((QueueStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool QueueStats::operator!=(const QueueStats &other) const { + return !(*this == other); +} + +size_t QueueStats::pack(uint8_t* buffer) { + struct of10::ofp_queue_stats *qs = (struct of10::ofp_queue_stats*) buffer; + qs->port_no = hton16(this->port_no_); + memset(qs->pad, 0x0, 2); + qs->queue_id = hton32(this->queue_id_); + qs->tx_bytes = hton64(this->tx_bytes_); + qs->tx_packets = hton64(this->tx_packets_); + qs->tx_errors = hton64(this->tx_errors_); + return 0; +} + +of_error QueueStats::unpack(uint8_t* buffer) { + struct of10::ofp_queue_stats *qs = (struct of10::ofp_queue_stats*) buffer; + this->port_no_ = ntoh16(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + this->tx_bytes_ = ntoh64(qs->tx_bytes); + this->tx_packets_ = ntoh64(qs->tx_packets); + this->tx_errors_ = ntoh64(qs->tx_errors); + return 0; +} + +} //End namespace of13 + +QueueProperty* QueueProperty::make_queue_of10_property(uint16_t property) { + switch (property) { + case (of10::OFPQT_NONE): { + return new QueuePropRate(); + } + case (of10::OFPQT_MIN_RATE): { + return new of10::QueuePropMinRate(); + } + } + return NULL; +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10/of10match.cc b/src/ovs/libfluid-msg/of10/of10match.cc new file mode 100644 index 00000000..72bc63f3 --- /dev/null +++ b/src/ovs/libfluid-msg/of10/of10match.cc @@ -0,0 +1,157 @@ +#include "libfluid-msg/of10/of10match.hh" + +namespace fluid_msg { + +namespace of10 { + +Match::Match() + : in_port_(0), + dl_vlan_(0), + dl_vlan_pcp_(0), + dl_type_(0), + nw_tos_(0), + nw_proto_(0), + tp_src_(0), + tp_dst_(0), + dl_src_(), + dl_dst_(), + nw_src_((uint32_t) 0), + nw_dst_((uint32_t) 0), + wildcards_(of10::OFPFW_ALL) { +} + +bool Match::operator==(const Match &other) const { + return ((this->in_port_ == other.in_port_) + && (this->wildcards_ == other.wildcards_) + && (this->dl_vlan_ == other.dl_vlan_) + && (this->dl_vlan_pcp_ == other.dl_vlan_pcp_) + && (this->dl_type_ == other.dl_type_) + && (this->nw_tos_ == other.nw_tos_) + && (this->nw_proto_ == other.nw_proto_) + && (this->tp_src_ == other.tp_src_) && (this->tp_dst_ == other.tp_dst_) + && (this->nw_src_ == other.nw_src_) && (this->nw_dst_ == other.nw_dst_) + && (this->dl_src_ == other.dl_src_) && (this->dl_dst_ == other.dl_dst_)); +} + +bool Match::operator!=(const Match &other) const { + return !(*this == other); +} + +void Match::wildcards(uint32_t wildcards) { + this->wildcards_ = wildcards; +} + +void Match::in_port(uint16_t in_port) { + this->in_port_ = in_port; + this->wildcards_ &= ~of10::OFPFW_IN_PORT; +} + +void Match::dl_src(const EthAddress &dl_src) { + this->dl_src_ = dl_src; + this->wildcards_ &= ~of10::OFPFW_DL_SRC; +} + +void Match::dl_dst(const EthAddress &dl_dst) { + this->dl_dst_ = dl_dst; + this->wildcards_ &= ~of10::OFPFW_DL_DST; +} + +void Match::dl_vlan(uint16_t dl_vlan) { + this->dl_vlan_ = dl_vlan; + this->wildcards_ &= ~of10::OFPFW_DL_VLAN; +} + +void Match::dl_vlan_pcp(uint8_t dl_vlan_pcp) { + this->dl_vlan_pcp_ = dl_vlan_pcp; + this->wildcards_ &= ~of10::OFPFW_DL_VLAN_PCP; +} + +void Match::dl_type(uint16_t dl_type) { + this->dl_type_ = dl_type; + this->wildcards_ &= ~of10::OFPFW_DL_TYPE; +} + +void Match::nw_tos(uint8_t nw_tos) { + this->nw_tos_ = nw_tos; + this->wildcards_ &= ~of10::OFPFW_NW_TOS; +} + +void Match::nw_proto(uint8_t nw_proto) { + this->nw_proto_ = nw_proto; + this->wildcards_ &= ~of10::OFPFW_NW_PROTO; +} + +void Match::nw_src(const IPAddress &nw_src) { + this->nw_src_ = nw_src; + this->wildcards_ &= ~of10::OFPFW_NW_SRC_MASK; +} + +void Match::nw_dst(const IPAddress &nw_dst) { + this->nw_dst_ = nw_dst; + this->wildcards_ &= ~of10::OFPFW_NW_DST_MASK; +} + +void Match::nw_src(const IPAddress &nw_src, uint32_t prefix) { + this->nw_src_ = nw_src; + uint32_t index = 32 - prefix; + this->wildcards_ &= ~of10::OFPFW_NW_SRC_MASK; + this->wildcards_ |= (index << of10::OFPFW_NW_SRC_SHIFT); +} + +void Match::nw_dst(const IPAddress &nw_dst, uint32_t prefix) { + this->nw_dst_ = nw_dst; + uint32_t index = 32 - prefix; + this->wildcards_ &= ~of10::OFPFW_NW_DST_MASK; + this->wildcards_ |= (index << of10::OFPFW_NW_DST_SHIFT); +} + +void Match::tp_src(uint16_t tp_src) { + this->tp_src_ = tp_src; + this->wildcards_ &= ~of10::OFPFW_TP_SRC; +} + +void Match::tp_dst(uint16_t tp_dst) { + this->tp_dst_ = tp_dst; + this->wildcards_ &= ~of10::OFPFW_TP_DST; +} + +size_t Match::pack(uint8_t *buffer) { + struct of10::ofp_match *m = (struct ofp_match*) buffer; + m->wildcards = hton32(this->wildcards_); + m->in_port = hton16(this->in_port_); + memcpy(m->dl_src, this->dl_src_.get_data(), OFP_ETH_ALEN); + memcpy(m->dl_dst, this->dl_dst_.get_data(), OFP_ETH_ALEN); + m->dl_vlan = hton16(this->dl_vlan_); + m->dl_vlan_pcp = this->dl_vlan_pcp_; + memset(m->pad1, 0x0, 1); + m->dl_type = hton16(this->dl_type_); + m->nw_tos = this->nw_tos_; + m->nw_proto = this->nw_proto_; + memset(m->pad2, 0x0, 2); + m->nw_src = hton32(this->nw_src_.getIPv4()); + m->nw_dst = hton32(this->nw_dst_.getIPv4()); + m->tp_src = hton16(this->tp_src_); + m->tp_dst = hton16(this->tp_dst_); + return 0; +} + +of_error Match::unpack(uint8_t *buffer) { + struct of10::ofp_match *m = (struct ofp_match*) buffer; + this->wildcards_ = ntoh32(m->wildcards); + this->in_port_ = ntoh16(m->in_port); + this->dl_src_.set_data(m->dl_src); + this->dl_dst_.set_data(m->dl_dst); + this->dl_vlan_ = ntoh16(m->dl_vlan); + this->dl_vlan_pcp_ = m->dl_vlan_pcp; + this->dl_type_ = ntoh16(m->dl_type); + this->nw_tos_ = m->nw_tos; + this->nw_proto_ = m->nw_proto; + this->nw_src_.setIPv4(ntoh32(m->nw_src)); + this->nw_dst_.setIPv4(ntoh32(m->nw_dst)); + this->tp_src_ = ntoh16(m->tp_src); + this->tp_dst_ = ntoh16(m->tp_dst); + return 0; +} + +} //End of namespace of10 +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of10msg.cc b/src/ovs/libfluid-msg/of10msg.cc new file mode 100644 index 00000000..c6f37378 --- /dev/null +++ b/src/ovs/libfluid-msg/of10msg.cc @@ -0,0 +1,1506 @@ +#include "libfluid-msg/of10msg.hh" + +namespace fluid_msg { + +namespace of10 { + +Hello::Hello() + : OFMsg(of10::OFP_VERSION, of10::OFPT_HELLO) { +} + +Hello::Hello(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_HELLO, xid) { +} + +uint8_t* Hello::pack() { + return OFMsg::pack(); +} + +of_error Hello::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +Error::Error() + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR) { + this->length_ = sizeof(struct ofp_fluid_error_msg); +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code) + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR, xid, err_type, code) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len) + : ErrorCommon(of10::OFP_VERSION, of10::OFPT_ERROR, xid, err_type, code, + data, data_len) { +} + +EchoRequest::EchoRequest(uint32_t xid) + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REQUEST, xid) { +} + +EchoReply::EchoReply(uint32_t xid) + : EchoCommon(of10::OFP_VERSION, of10::OFPT_ECHO_REPLY, xid) { +} + +Vendor::Vendor() + : OFMsg(of10::OFP_VERSION, of10::OFPT_VENDOR), + vendor_(0) { + this->length_ = sizeof(struct of10::ofp_vendor_header); +} + +Vendor::Vendor(uint32_t xid, uint32_t vendor) + : OFMsg(of10::OFP_VERSION, of10::OFPT_VENDOR, xid), + vendor_(vendor) { + this->length_ = sizeof(struct of10::ofp_vendor_header); +} + +uint8_t* Vendor::pack() { + uint8_t * buffer = OFMsg::pack(); + struct of10::ofp_vendor_header* v = (struct of10::ofp_vendor_header*) buffer; + v->vendor = hton32(this->vendor_); + return buffer; +} + +of_error Vendor::unpack(uint8_t *buffer) { + struct of10::ofp_vendor_header* v = (struct of10::ofp_vendor_header*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_vendor_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->vendor_ = ntoh32(v->vendor); + return 0; +} + +FeaturesRequest::FeaturesRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_FEATURES_REQUEST) { +} + +FeaturesRequest::FeaturesRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_FEATURES_REQUEST, xid) { +} + +uint8_t* FeaturesRequest::pack() { + return OFMsg::pack(); +} + +of_error FeaturesRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +FeaturesReply::FeaturesReply() + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, 0, 0, 0, + 0, 0) { + this->length_ = sizeof(struct of10::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint32_t capabilities, + uint32_t actions) + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities) { + this->actions_ = actions; + this->length_ = sizeof(struct of10::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint32_t capabilities, + uint32_t actions, std::vector ports) + : FeaturesReplyCommon(of10::OFP_VERSION, of10::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities) { + this->actions_ = actions; + this->ports_ = ports; + this->length_ = sizeof(struct of10::ofp_switch_features) + ports_length(); +} + +bool FeaturesReply::operator==(const FeaturesReply &other) const { + return ((FeaturesReplyCommon::operator==(other)) + && (this->actions_ == other.actions_) && (this->ports_ == other.ports_)); +} + +bool FeaturesReply::operator!=(const FeaturesReply &other) const { + return !(*this == other); +} + +uint8_t* FeaturesReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_switch_features *fr = + (struct of10::ofp_switch_features*) buffer; + fr->datapath_id = hton64(this->datapath_id_); + fr->n_buffers = hton32(this->n_buffers_); + fr->n_tables = this->n_tables_; + memset(fr->pad, 0x0, 3); + fr->capabilities = hton32(this->capabilities_); + fr->actions = hton32(this->actions_); + uint8_t *p = buffer + sizeof(struct of10::ofp_switch_features); + for (std::vector::iterator it = this->ports_.begin(), end = + this->ports_.end(); it != end; ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_phy_port); + } + return buffer; +} + +of_error FeaturesReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + struct of10::ofp_switch_features *fr = + (struct of10::ofp_switch_features*) buffer; + this->datapath_id_ = ntoh64(fr->datapath_id); + this->n_buffers_ = ntoh32(fr->n_buffers); + this->n_tables_ = fr->n_tables; + this->capabilities_ = ntoh32(fr->capabilities); + this->actions_ = ntoh32(fr->actions); + size_t len = this->length_ - sizeof(struct of10::ofp_switch_features); + uint8_t *p = buffer + sizeof(struct of10::ofp_switch_features); + while (len) { + of10::Port port; + port.unpack(p); + len -= sizeof(struct of10::ofp_phy_port); + this->ports_.push_back(port); + p += sizeof(struct of10::ofp_phy_port); + } + return 0; +} + +void FeaturesReply::ports(std::vector ports) { + this->ports_ = ports; + this->length_ += ports_length(); +} + +size_t FeaturesReply::ports_length() { + return this->ports_.size() * sizeof(struct of10::ofp_phy_port); +} + +void FeaturesReply::add_port(of10::Port port) { + this->ports_.push_back(port); + this->length_ += sizeof(struct of10::ofp_phy_port); +} + +GetConfigRequest::GetConfigRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REQUEST) { +} + +GetConfigRequest::GetConfigRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REQUEST, xid) { +} + +uint8_t* GetConfigRequest::pack() { + return OFMsg::pack(); +} + +of_error GetConfigRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + return 0; +} + +GetConfigReply::GetConfigReply() + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REPLY, 0, 0, + 0) { +} + +GetConfigReply::GetConfigReply(uint32_t xid, uint16_t flags, + uint16_t miss_send_len) + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_GET_CONFIG_REPLY, xid, + flags, miss_send_len) { +} + +SetConfig::SetConfig() + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_SET_CONFIG) { +} +; + +SetConfig::SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : SwitchConfigCommon(of10::OFP_VERSION, of10::OFPT_SET_CONFIG, xid, flags, + miss_send_len) { +} + +FlowMod::FlowMod() + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD), + command_(0), + out_port_(0) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, of10::Match match) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port), + match_(match) { + this->length_ = sizeof(struct of10::ofp_flow_mod); +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint16_t command, + uint16_t idle_timeout, uint16_t hard_timeout, uint16_t priority, + uint32_t buffer_id, uint16_t out_port, uint16_t flags, of10::Match match, + ActionList actions) + : FlowModCommon(of10::OFP_VERSION, of10::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + command_(command), + out_port_(out_port), + match_(match), + actions_(actions) { + this->length_ = sizeof(struct of10::ofp_flow_mod) + actions.length(); +} + +bool FlowMod::operator==(const FlowMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) && + (this->out_port_ == other.out_port_) && (this->match_ == other.match_) + && (this->actions_ == other.actions_)); +} + +bool FlowMod::operator!=(const FlowMod &other) const { + return !(*this == other); +} + +uint8_t* FlowMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_flow_mod *fm = (struct of10::ofp_flow_mod*) buffer; + this->match_.pack(buffer + sizeof(struct ofp_fluid_header)); + fm->cookie = hton64(this->cookie_); + fm->command = hton16(this->command_); + fm->idle_timeout = hton16(this->idle_timeout_); + fm->hard_timeout = hton16(this->hard_timeout_); + fm->priority = hton16(this->priority_); + fm->buffer_id = hton32(this->buffer_id_); + fm->out_port = hton16(this->out_port_); + fm->flags = hton16(this->flags_); + this->actions_.pack(buffer + sizeof(struct of10::ofp_flow_mod)); + return buffer; +} + +of_error FlowMod::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + struct of10::ofp_flow_mod *fm = (struct of10::ofp_flow_mod*) buffer; + if (fm->header.length < sizeof(struct of10::ofp_flow_mod)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->match_.unpack(buffer + sizeof(struct ofp_fluid_header)); + this->cookie_ = ntoh64(fm->cookie); + this->command_ = ntoh16(fm->command); + this->idle_timeout_ = ntoh16(fm->idle_timeout); + this->hard_timeout_ = ntoh16(fm->hard_timeout); + this->priority_ = ntoh16(fm->priority); + this->buffer_id_ = ntoh32(fm->buffer_id); + this->out_port_ = ntoh16(fm->out_port); + this->flags_ = ntoh16(fm->flags); + this->actions_.length(this->length_ - sizeof(struct of10::ofp_flow_mod)); + this->actions_.unpack10(buffer + sizeof(struct of10::ofp_flow_mod)); + return 0; +} + +void FlowMod::actions(const ActionList& actions) { + this->actions_ = actions; + this->length_ += this->actions_.length(); +} + +void FlowMod::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void FlowMod::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +PacketOut::PacketOut() + : PacketOutCommon(of10::OFP_VERSION, of10::OFPT_PACKET_OUT), + in_port_(0) { + this->length_ = sizeof(struct of10::ofp_packet_out); +} + +PacketOut::PacketOut(uint32_t xid, uint32_t buffer_id, uint16_t in_port) + : PacketOutCommon(of10::OFP_VERSION, of10::OFPT_PACKET_OUT, xid, buffer_id), + in_port_(in_port) { + this->length_ = sizeof(struct of10::ofp_packet_out); +} + +bool PacketOut::operator==(const PacketOut &other) const { + return ((PacketOutCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketOut::operator!=(const PacketOut &other) const { + return !(*this == other); +} + +uint8_t* PacketOut::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_packet_out *po = (struct of10::ofp_packet_out*) buffer; + po->buffer_id = hton32(this->buffer_id_); + po->in_port = hton16(this->in_port_); + po->actions_len = hton16(this->actions_len_); + this->actions_.pack(buffer + sizeof(struct of10::ofp_packet_out)); + this->data_len_ = this->length_ + - (sizeof(struct of10::ofp_packet_out) + this->actions_len_); + if (this->buffer_id_ == of10::OFP_NO_BUFFER) { + uint8_t *p = buffer + sizeof(struct of10::ofp_packet_out) + + this->actions_len_; + memcpy(p, this->data_, this->data_len_); + } + return buffer; +} + +of_error PacketOut::unpack(uint8_t *buffer) { + struct of10::ofp_packet_out *po = (struct of10::ofp_packet_out*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_packet_out)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->buffer_id_ = ntoh32(po->buffer_id); + this->in_port_ = ntoh16(po->in_port); + this->actions_len_ = ntoh16(po->actions_len); + this->actions_.length(this->actions_len_); + uint8_t * p = buffer + sizeof(struct of10::ofp_packet_out); + this->actions_.unpack10(p); + this->data_len_ = this->length_ + - (sizeof(struct of10::ofp_packet_out) + this->actions_len_); + if (this->buffer_id_ == of10::OFP_NO_BUFFER) { + /*Reuse p to calculate the packet data position */ + p = buffer + sizeof(struct of10::ofp_packet_out) + this->actions_len_; + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, p, this->data_len_); + } + } + return 0; +} + +PacketIn::PacketIn() + : PacketInCommon(of10::OFP_VERSION, of10::OFPT_PACKET_IN), + in_port_(0) { + this->length_ = sizeof(struct of10::ofp_packet_in) - 2; +} + +PacketIn::PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t in_port, + uint16_t total_len, uint8_t reason) + : PacketInCommon(of10::OFP_VERSION, of10::OFPT_PACKET_IN, xid, buffer_id, + total_len, reason), + in_port_(in_port) { + this->length_ = sizeof(struct of10::ofp_packet_in) - 2; +} + +bool PacketIn::operator==(const PacketIn &other) const { + return ((PacketInCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketIn::operator!=(const PacketIn &other) const { + return !(*this == other); +} + +uint8_t* PacketIn::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_packet_in *pi = (struct of10::ofp_packet_in*) buffer; + pi->buffer_id = hton32(this->buffer_id_); + pi->total_len = hton16(this->total_len_); + pi->in_port = hton16(this->in_port_); + pi->reason = this->reason_; + memset(&pi->pad, 0x0, 1); + if (this->data_len_) { + memcpy(pi->data, this->data_, this->data_len_); + } + return buffer; +} + +of_error PacketIn::unpack(uint8_t *buffer) { + struct of10::ofp_packet_in *pi = (struct of10::ofp_packet_in*) buffer; + OFMsg::unpack(buffer); + this->buffer_id_ = ntoh32(pi->buffer_id); + this->total_len_ = ntoh16(pi->total_len); + this->in_port_ = ntoh16(pi->in_port); + this->reason_ = pi->reason; + this->data_len_ = this->length_ - (sizeof(struct of10::ofp_packet_in) - 2); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, pi->data, this->data_len_); + } + return 0; +} + +FlowRemoved::FlowRemoved() + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count) + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, + uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count, + of10::Match match) + : FlowRemovedCommon(of10::OFP_VERSION, of10::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count), + match_(match) { + this->length_ = sizeof(struct of10::ofp_flow_removed); +} + +bool FlowRemoved::operator==(const FlowRemoved &other) const { + return ((FlowRemovedCommon::operator==(other)) + && (this->match_ == other.match_)); +} + +bool FlowRemoved::operator!=(const FlowRemoved &other) const { + return !(*this == other); +} + +uint8_t* FlowRemoved::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_flow_removed *fr = (struct of10::ofp_flow_removed*) buffer; + this->match_.pack(buffer + sizeof(struct ofp_fluid_header)); + fr->cookie = hton64(this->cookie_); + fr->priority = hton16(this->priority_); + fr->reason = this->reason_; + memset(&fr->pad, 0x0, 1); + fr->duration_sec = hton32(this->duration_sec_); + fr->duration_nsec = hton32(this->duration_nsec_); + fr->idle_timeout = hton16(this->idle_timeout_); + memset(fr->pad, 0x0, 2); + fr->packet_count = hton64(this->packet_count_); + fr->byte_count = hton64(this->byte_count_); + return buffer; +} + +of_error FlowRemoved::unpack(uint8_t *buffer) { + struct of10::ofp_flow_removed *fr = (struct of10::ofp_flow_removed*) buffer; + OFMsg::unpack(buffer); + this->match_.unpack(buffer + sizeof(struct ofp_fluid_header)); + this->cookie_ = ntoh64(fr->cookie); + this->priority_ = ntoh16(fr->priority); + this->reason_ = fr->reason; + this->duration_sec_ = ntoh32(fr->duration_sec); + this->duration_nsec_ = ntoh32(fr->duration_nsec); + this->idle_timeout_ = ntoh16(fr->idle_timeout); + this->packet_count_ = ntoh64(fr->packet_count); + this->byte_count_ = ntoh64(fr->byte_count); + return 0; +} + +PortStatus::PortStatus() + : PortStatusCommon(of10::OFP_VERSION, of10::OFPT_PORT_STATUS) { + this->length_ = sizeof(struct of10::ofp_port_status); +} + +PortStatus::PortStatus(uint32_t xid, uint8_t reason, of10::Port desc) + : PortStatusCommon(of10::OFP_VERSION, of10::OFPT_PORT_STATUS, xid, reason), + desc_(desc) { + this->length_ = sizeof(struct of10::ofp_port_status); +} + +bool PortStatus::operator==(const PortStatus &other) const { + return ((PortStatusCommon::operator==(other)) + && (this->desc_ == other.desc_)); +} + +bool PortStatus::operator!=(const PortStatus &other) const { + return !(*this == other); +} + +uint8_t* PortStatus::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_port_status *ps = (struct of10::ofp_port_status *) buffer; + ps->reason = this->reason_; + memset(ps->pad, 0x0, 7); + this->desc_.pack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return buffer; +} + +of_error PortStatus::unpack(uint8_t *buffer) { + struct of10::ofp_port_status *ps = (struct of10::ofp_port_status *) buffer; + OFMsg::unpack(buffer); + this->reason_ = ps->reason; + this->desc_.unpack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return 0; +} + +PortMod::PortMod() + : PortModCommon(of10::OFP_VERSION, of10::OFPT_PORT_MOD), + port_no_(0) { + this->length_ = sizeof(struct of10::ofp_port_mod); +} +; + +PortMod::PortMod(uint32_t xid, uint16_t port_no, EthAddress hw_addr, + uint32_t config, uint32_t mask, uint32_t advertise) + : PortModCommon(of10::OFP_VERSION, of10::OFPT_PORT_MOD, xid, hw_addr, + config, mask, advertise), + port_no_(port_no) { + this->length_ = sizeof(struct of10::ofp_port_mod); +} + +bool PortMod::operator==(const PortMod &other) const { + return ((PortModCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortMod::operator!=(const PortMod &other) const { + return !(*this == other); +} + +uint8_t* PortMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_port_mod *pm = (struct of10::ofp_port_mod *) buffer; + pm->port_no = hton16(this->port_no_); + memcpy(pm->hw_addr, hw_addr_.get_data(), OFP_ETH_ALEN); + pm->config = hton32(this->config_); + pm->mask = hton32(this->mask_); + pm->advertise = hton32(this->advertise_); + memset(pm->pad, 0x0, 4); + return buffer; +} + +of_error PortMod::unpack(uint8_t* buffer) { + struct of10::ofp_port_mod *pm = (struct of10::ofp_port_mod *) buffer; + if (pm->header.length < sizeof(struct of10::ofp_port_mod)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + OFMsg::unpack(buffer); + this->port_no_ = ntoh16(pm->port_no); + this->hw_addr_ = EthAddress(pm->hw_addr); + this->config_ = ntoh32(pm->config); + this->mask_ = ntoh32(pm->mask); + this->advertise_ = ntoh32(pm->advertise); + return 0; +} + +StatsRequest::StatsRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST), + stats_type_(0), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +StatsRequest::StatsRequest(uint16_t type) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST), + stats_type_(type), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +StatsRequest::StatsRequest(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REQUEST, xid), + stats_type_(type), + flags_(flags) { + this->length_ = sizeof(struct of10::ofp_stats_request); +} + +bool StatsRequest::operator==(const StatsRequest &other) const { + return ((OFMsg::operator==(other)) + && (this->stats_type_ == other.stats_type_) + && (this->flags_ == other.flags_)); +} + +bool StatsRequest::operator!=(const StatsRequest &other) const { + return !(*this == other); +} + +uint8_t* StatsRequest::pack() { + uint8_t *buffer = OFMsg::pack(); + struct of10::ofp_stats_request * sr = + (struct of10::ofp_stats_request *) buffer; + + sr->type = hton16(this->stats_type_); + sr->flags = hton16(this->flags_); + return buffer; +} + +of_error StatsRequest::unpack(uint8_t *buffer) { + struct of10::ofp_stats_request * sr = + (struct of10::ofp_stats_request *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of10::ofp_stats_request)) { + return openflow_error(of10::OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->stats_type_ = ntoh16(sr->type); + this->flags_ = ntoh16(sr->flags); + return 0; +} + +StatsReply::StatsReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY), + stats_type_(0), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +StatsReply::StatsReply(uint16_t type) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY), + stats_type_(type), + flags_(0) { + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +StatsReply::StatsReply(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of10::OFP_VERSION, of10::OFPT_STATS_REPLY, xid) { + this->stats_type_ = type; + this->flags_ = flags; + this->length_ = sizeof(struct of10::ofp_stats_reply); +} + +bool StatsReply::operator==(const StatsReply &other) const { + return ((OFMsg::operator==(other)) + && (this->stats_type_ == other.stats_type_) + && (this->flags_ == other.flags_)); +} + +bool StatsReply::operator!=(const StatsReply &other) const { + return !(*this == other); +} + +uint8_t* StatsReply::pack() { + uint8_t *buffer = OFMsg::pack(); + struct of10::ofp_stats_reply * sr = (struct of10::ofp_stats_reply *) buffer; + sr->type = hton16(this->stats_type_); + sr->flags = hton16(this->flags_); + return buffer; +} + +of_error StatsReply::unpack(uint8_t *buffer) { + struct of10::ofp_stats_reply * sr = (struct of10::ofp_stats_reply *) buffer; + OFMsg::unpack(buffer); + this->stats_type_ = ntoh16(sr->type); + this->flags_ = ntoh16(sr->flags); + return 0; +} + +StatsRequestDesc::StatsRequestDesc() + : StatsRequest(OFPST_DESC) { +} + +StatsRequestDesc::StatsRequestDesc(uint32_t xid, uint16_t flags) + : StatsRequest(xid, of10::OFPST_DESC, flags) { +} + +uint8_t* StatsRequestDesc::pack() { + uint8_t* buffer = StatsRequest::pack(); + return buffer; +} + +of_error StatsRequestDesc::unpack(uint8_t *buffer) { + return StatsRequest::unpack(buffer); +} + +StatsReplyDesc::StatsReplyDesc() + : StatsReply(OFPST_DESC) { + this->length_ += sizeof(struct ofp_desc); +} + +StatsReplyDesc::StatsReplyDesc(uint32_t xid, uint16_t flags, SwitchDesc desc) + : StatsReply(xid, of10::OFPST_DESC, flags), + desc_(desc) { + this->length_ += sizeof(struct ofp_desc); +} + +StatsReplyDesc::StatsReplyDesc(uint32_t xid, uint16_t flags, + std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc) + : StatsReply(xid, of10::OFPST_DESC, flags), + desc_(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) { + this->length_ += sizeof(struct ofp_desc); +} + +bool StatsReplyDesc::operator==(const StatsReplyDesc &other) const { + return ((StatsReply::operator==(other)) && (this->desc_ == other.desc_)); +} + +bool StatsReplyDesc::operator!=(const StatsReplyDesc &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyDesc::pack() { + uint8_t* buffer = StatsReply::pack(); + this->desc_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + return buffer; +} + +of_error StatsReplyDesc::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + return this->desc_.unpack(buffer + sizeof(struct of10::ofp_stats_reply)); +} + +void StatsReplyDesc::desc(SwitchDesc desc) { + this->desc_ = desc; + this->length_ += sizeof(struct ofp_desc); +} + +StatsRequestFlow::StatsRequestFlow() + : StatsRequest(OFPST_FLOW) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +StatsRequestFlow::StatsRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_FLOW, flags), + table_id_(table_id), + out_port_(out_port) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +StatsRequestFlow::StatsRequestFlow(uint32_t xid, uint16_t flags, + of10::Match match, uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + match_(match) { + this->length_ += sizeof(struct of10::ofp_flow_stats_request); +} + +bool StatsRequestFlow::operator==(const StatsRequestFlow &other) const { + return ((StatsRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->match_ == other.match_)); +} + +bool StatsRequestFlow::operator!=(const StatsRequestFlow &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestFlow::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_flow_stats_request *fs = + (struct of10::ofp_flow_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + this->match_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->out_port = hton16(this->out_port_); + return buffer; +} + +of_error StatsRequestFlow::unpack(uint8_t *buffer) { + struct of10::ofp_flow_stats_request *fs = + (struct of10::ofp_flow_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_flow_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = hton16(fs->out_port); + return this->match_.unpack(buffer + sizeof(struct of10::ofp_stats_request)); +} + +StatsReplyFlow::StatsReplyFlow() + : StatsReply(OFPST_FLOW) { +} + +StatsReplyFlow::StatsReplyFlow(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_FLOW, flags) { +} +StatsReplyFlow::StatsReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats) + : StatsReply(xid, of10::OFPST_FLOW, flags), + flow_stats_(flow_stats) { + this->length_ += flow_stats.size() * sizeof(struct ofp_flow_stats); +} + +bool StatsReplyFlow::operator==(const StatsReplyFlow &other) const { + return ((StatsReply::operator==(other)) + && (this->flow_stats_ == other.flow_stats_)); +} + +bool StatsReplyFlow::operator!=(const StatsReplyFlow &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyFlow::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_request); + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error StatsReplyFlow::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + FlowStats stat; + stat.unpack(p); + this->flow_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void StatsReplyFlow::flow_stats(std::vector flow_stats) { + this->flow_stats_ = flow_stats; + this->length_ += this->flow_stats_.size() * sizeof(struct ofp_flow_stats); +} + +void StatsReplyFlow::add_flow_stats(of10::FlowStats stats) { + this->flow_stats_.push_back(stats); + this->length_ += stats.length(); +} + +StatsRequestAggregate::StatsRequestAggregate() + : StatsRequest(OFPST_AGGREGATE) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +StatsRequestAggregate::StatsRequestAggregate(uint32_t xid, uint16_t flags, + uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_AGGREGATE, flags) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +StatsRequestAggregate::StatsRequestAggregate(uint32_t xid, uint16_t flags, + of10::Match match, uint8_t table_id, uint16_t out_port) + : StatsRequest(xid, of10::OFPST_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + match_(match) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_request); +} + +bool StatsRequestAggregate::operator==( + const StatsRequestAggregate &other) const { + return ((StatsRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->match_ == other.match_)); +} + +bool StatsRequestAggregate::operator!=( + const StatsRequestAggregate &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestAggregate::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_aggregate_stats_request *fs = + (struct of10::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + this->match_.pack(buffer + sizeof(struct of10::ofp_stats_request)); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->out_port = hton16(this->out_port_); + return buffer; +} + +of_error StatsRequestAggregate::unpack(uint8_t *buffer) { + struct of10::ofp_aggregate_stats_request *fs = + (struct of10::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + + sizeof(of10::ofp_aggregate_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = hton16(fs->out_port); + return this->match_.unpack(buffer + sizeof(struct of10::ofp_stats_request)); +} + +StatsReplyAggregate::StatsReplyAggregate() + : StatsReply(OFPST_AGGREGATE) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_reply); +} + +StatsReplyAggregate::StatsReplyAggregate(uint32_t xid, uint16_t flags, + uint64_t packet_count, uint64_t byte_count, uint32_t flow_count) + : StatsReply(xid, of10::OFPST_AGGREGATE, flags), + packet_count_(packet_count), + byte_count_(byte_count), + flow_count_(flow_count) { + this->length_ += sizeof(struct of10::ofp_aggregate_stats_reply); +} + +bool StatsReplyAggregate::operator==(const StatsReplyAggregate &other) const { + return ((StatsReply::operator==(other)) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->flow_count_ == other.flow_count_)); +} + +bool StatsReplyAggregate::operator!=(const StatsReplyAggregate &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyAggregate::pack() { + uint8_t* buffer = StatsReply::pack(); + struct of10::ofp_aggregate_stats_reply *ar = + (struct of10::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of10::ofp_stats_reply)); + ar->packet_count = hton64(this->packet_count_); + ar->byte_count = hton64(this->byte_count_); + ar->flow_count = hton32(this->flow_count_); + memset(ar->pad, 0x0, 4); + return buffer; +} + +of_error StatsReplyAggregate::unpack(uint8_t *buffer) { + struct of10::ofp_aggregate_stats_reply *ar = + (struct of10::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of10::ofp_stats_reply)); + StatsReply::unpack(buffer); + this->packet_count_ = ntoh64(ar->packet_count); + this->byte_count_ = ntoh64(ar->byte_count); + this->flow_count_ = ntoh32(ar->flow_count); + return 0; +} + +StatsRequestTable::StatsRequestTable() + : StatsRequest(OFPST_TABLE) { +} + +StatsRequestTable::StatsRequestTable(uint32_t xid, uint16_t flags) + : StatsRequest(xid, of10::OFPST_TABLE, flags) { +} + +uint8_t* StatsRequestTable::pack() { + uint8_t* buffer = StatsRequest::pack(); + return buffer; +} + +of_error StatsRequestTable::unpack(uint8_t *buffer) { + return StatsRequest::unpack(buffer); +} + +StatsReplyTable::StatsReplyTable() + : StatsReply(OFPST_TABLE) { +} + +StatsReplyTable::StatsReplyTable(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_TABLE, flags) { +} + +StatsReplyTable::StatsReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats) + : StatsReply(xid, of10::OFPST_TABLE, flags), + table_stats_(table_stats) { + this->length_ += table_stats.size() * sizeof(struct of10::ofp_table_stats); +} + +bool StatsReplyTable::operator==(const StatsReplyTable &other) const { + return ((StatsReply::operator==(other)) + && (this->table_stats_ == other.table_stats_)); +} + +bool StatsReplyTable::operator!=(const StatsReplyTable &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyTable::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = this->table_stats_.begin(); + it != this->table_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_table_stats); + } + return buffer; +} + +of_error StatsReplyTable::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + TableStats stat; + stat.unpack(p); + this->table_stats_.push_back(stat); + p += sizeof(struct of10::ofp_table_stats); + len -= sizeof(struct of10::ofp_table_stats); + } + return 0; +} + +void StatsReplyTable::table_stats(std::vector table_stats) { + this->table_stats_ = table_stats; + this->length_ += table_stats.size() * sizeof(struct of10::ofp_table_stats); +} + +void StatsReplyTable::add_table_stat(of10::TableStats stat) { + this->table_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_table_stats); +} + +StatsRequestPort::StatsRequestPort() + : StatsRequest(OFPST_PORT) { + this->length_ += sizeof(struct of10::ofp_port_stats_request); +} + +StatsRequestPort::StatsRequestPort(uint32_t xid, uint16_t flags, + uint16_t port_no) + : StatsRequest(xid, of10::OFPST_PORT, flags), + port_no_(port_no) { + this->length_ += sizeof(struct of10::ofp_port_stats_request); +} +; + +bool StatsRequestPort::operator==(const StatsRequestPort &other) const { + return ((StatsRequest::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool StatsRequestPort::operator!=(const StatsRequestPort &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestPort::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_port_stats_request *ps = + (struct of10::ofp_port_stats_request *) (buffer + + sizeof(struct of10::ofp_stats_request)); + ps->port_no = hton16(this->port_no_); + memset(ps->pad, 0x0, 6); + return buffer; +} + +of_error StatsRequestPort::unpack(uint8_t *buffer) { + struct of10::ofp_port_stats_request *ps = + (struct of10::ofp_port_stats_request *) (buffer + + sizeof(struct of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_port_stats_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh16(ps->port_no); + return 0; +} + +StatsReplyPort::StatsReplyPort() + : StatsReply(OFPST_PORT) { +} + +StatsReplyPort::StatsReplyPort(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_PORT, flags) { +} + +StatsReplyPort::StatsReplyPort(uint32_t xid, uint16_t flags, + std::vector port_stats) + : StatsReply(xid, of10::OFPST_PORT, flags), + port_stats_(port_stats) { + this->length_ += port_stats.size() * sizeof(struct of10::ofp_port_stats); +} + +bool StatsReplyPort::operator==(const StatsReplyPort &other) const { + return ((StatsReply::operator==(other)) + && (this->port_stats_ == other.port_stats_)); +} + +bool StatsReplyPort::operator!=(const StatsReplyPort &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyPort::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = this->port_stats_.begin(); + it != this->port_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_port_stats); + } + return buffer; +} + +of_error StatsReplyPort::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_request); + while (len) { + of10::PortStats stat; + stat.unpack(p); + this->port_stats_.push_back(stat); + p += sizeof(struct of10::ofp_port_stats); + len -= sizeof(struct of10::ofp_port_stats); + } + return 0; +} + +void StatsReplyPort::port_stats(std::vector port_stats) { + this->port_stats_ = port_stats; + this->length_ += port_stats.size() * sizeof(struct of10::ofp_port_stats); +} + +void StatsReplyPort::add_port_stat(of10::PortStats stat) { + this->port_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_port_stats); +} + +StatsRequestQueue::StatsRequestQueue() + : StatsRequest(OFPST_QUEUE) { + this->length_ += sizeof(struct of10::ofp_queue_stats_request); +} + +StatsRequestQueue::StatsRequestQueue(uint32_t xid, uint16_t flags, + uint16_t port_no, uint32_t queue_id) + : StatsRequest(xid, of10::OFPST_QUEUE, flags), + port_no_(port_no), + queue_id_(queue_id) { + this->length_ += sizeof(struct of10::ofp_queue_stats_request); +} + +bool StatsRequestQueue::operator==(const StatsRequestQueue &other) const { + return ((StatsRequest::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->queue_id_ == other.queue_id_)); +} + +bool StatsRequestQueue::operator!=(const StatsRequestQueue &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestQueue::pack() { + uint8_t* buffer = StatsRequest::pack(); + struct of10::ofp_queue_stats_request* qs = + (of10::ofp_queue_stats_request*) (buffer + + sizeof(of10::ofp_stats_request)); + qs->port_no = hton16(this->port_no_); + memset(qs->pad, 0x0, 2); + qs->queue_id = hton32(this->queue_id_); + return buffer; +} + +of_error StatsRequestQueue::unpack(uint8_t *buffer) { + struct of10::ofp_queue_stats_request* qs = + (of10::ofp_queue_stats_request*) (buffer + + sizeof(of10::ofp_stats_request)); + StatsRequest::unpack(buffer); + if (this->length_ + < sizeof(ofp_stats_request) + sizeof(of10::ofp_queue_stats_request)) { + return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + } + this->port_no_ = hton16(qs->port_no); + this->queue_id_ = hton32(qs->queue_id); + return 0; +} + +StatsReplyQueue::StatsReplyQueue() + : StatsReply(OFPST_QUEUE) { +} + +StatsReplyQueue::StatsReplyQueue(uint32_t xid, uint16_t flags) + : StatsReply(xid, of10::OFPST_QUEUE, flags) { +} + +StatsReplyQueue::StatsReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats) + : StatsReply(xid, of10::OFPST_QUEUE, flags), + queue_stats_(queue_stats) { + this->length_ += sizeof(struct of10::ofp_queue_stats); +} + +bool StatsReplyQueue::operator==(const StatsReplyQueue &other) const { + return ((StatsReply::operator==(other)) + && (this->queue_stats_ == other.queue_stats_)); +} + +bool StatsReplyQueue::operator!=(const StatsReplyQueue &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyQueue::pack() { + uint8_t* buffer = StatsReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + for (std::vector::iterator it = + this->queue_stats_.begin(); it != this->queue_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of10::ofp_queue_stats); + } + return buffer; +} + +of_error StatsReplyQueue::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint8_t len = this->length_ - sizeof(struct ofp_stats_reply); + uint8_t *p = buffer + sizeof(struct ofp_stats_reply); + while (len) { + of10::QueueStats stat; + stat.unpack(p); + this->queue_stats_.push_back(stat); + p += sizeof(struct of10::ofp_queue_stats); + len -= sizeof(struct of10::ofp_queue_stats); + } + return 0; +} + +void StatsReplyQueue::queue_stats(std::vector queue_stats) { + this->queue_stats_ = queue_stats; + this->length_ += queue_stats.size() * sizeof(struct of10::ofp_queue_stats); +} + +void StatsReplyQueue::add_queue_stat(of10::QueueStats stat) { + this->queue_stats_.push_back(stat); + this->length_ += sizeof(struct of10::ofp_queue_stats); +} + +StatsRequestVendor::StatsRequestVendor() + : StatsRequest(OFPST_VENDOR) { + this->length_ += 4; +} + +StatsRequestVendor::StatsRequestVendor(uint32_t xid, uint16_t flags, + uint32_t vendor) + : StatsRequest(xid, of10::OFPST_VENDOR, flags), + vendor_(vendor) { + this->length_ += 4; +} + +bool StatsRequestVendor::operator==(const StatsRequestVendor &other) const { + return ((StatsRequest::operator==(other)) + && (this->vendor_ == other.vendor_)); +} + +bool StatsRequestVendor::operator!=(const StatsRequestVendor &other) const { + return !(*this == other); +} + +uint8_t* StatsRequestVendor::pack() { + uint8_t* buffer = StatsRequest::pack(); + uint32_t vendor = hton32(this->vendor_); + memcpy(buffer + sizeof(struct of10::ofp_stats_request), &vendor, + sizeof(uint32_t)); + return buffer; +} + +of_error StatsRequestVendor::unpack(uint8_t *buffer) { + StatsRequest::unpack(buffer); + uint32_t vendor; + memcpy(&vendor, buffer + sizeof(struct of10::ofp_stats_request), + sizeof(uint32_t)); + this->vendor_ = ntoh32(this->vendor_); + return 0; +} + +StatsReplyVendor::StatsReplyVendor() + : StatsReply(OFPST_VENDOR) { + this->length_ += 4; +} + +StatsReplyVendor::StatsReplyVendor(uint32_t xid, uint16_t flags, + uint32_t vendor) + : StatsReply(xid, of10::OFPST_VENDOR, flags), + vendor_(vendor) { + this->length_ += 4; +} + +bool StatsReplyVendor::operator==(const StatsReplyVendor &other) const { + return ((StatsReply::operator==(other)) && (this->vendor_ == other.vendor_)); +} + +bool StatsReplyVendor::operator!=(const StatsReplyVendor &other) const { + return !(*this == other); +} + +uint8_t* StatsReplyVendor::pack() { + uint8_t* buffer = StatsReply::pack(); + uint32_t vendor = hton32(this->vendor_); + memcpy(buffer + sizeof(struct of10::ofp_stats_reply), &vendor, + sizeof(uint32_t)); + return buffer; +} + +of_error StatsReplyVendor::unpack(uint8_t *buffer) { + StatsReply::unpack(buffer); + uint32_t vendor; + memcpy(&vendor, buffer + sizeof(struct of10::ofp_stats_reply), + sizeof(uint32_t)); + this->vendor_ = ntoh32(this->vendor_); + return 0; +} + +QueueGetConfigRequest::QueueGetConfigRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REQUEST) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_request); +} + +QueueGetConfigRequest::QueueGetConfigRequest(uint32_t xid, uint16_t port) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REQUEST, xid), + port_(port) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_request); +} + +bool QueueGetConfigRequest::operator==( + const QueueGetConfigRequest &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_)); +} + +bool QueueGetConfigRequest::operator!=( + const QueueGetConfigRequest &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_queue_get_config_request * qc = + (struct of10::ofp_queue_get_config_request*) buffer; + qc->port = hton16(this->port_); + memset(qc->pad, 0x0, 2); + return buffer; +} + +of_error QueueGetConfigRequest::unpack(uint8_t *buffer) { + struct of10::ofp_queue_get_config_request * qc = + (struct of10::ofp_queue_get_config_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(ofp_queue_get_config_request)) { + return openflow_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + this->port_ = ntoh16(qc->port); + return 0; +} + +QueueGetConfigReply::QueueGetConfigReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues) + : OFMsg(of10::OFP_VERSION, of10::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port), + queues_(queues) { + this->length_ = sizeof(struct of10::ofp_queue_get_config_reply) + + queues_len(); +} + +bool QueueGetConfigReply::operator==(const QueueGetConfigReply &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_) + && (this->queues_ == other.queues_)); +} + +bool QueueGetConfigReply::operator!=(const QueueGetConfigReply &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of10::ofp_queue_get_config_reply *qr = + (struct of10::ofp_queue_get_config_reply *) buffer; + qr->port = hton16(this->port_); + memset(qr->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of10::ofp_queue_get_config_reply); + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error QueueGetConfigReply::unpack(uint8_t *buffer) { + struct of10::ofp_queue_get_config_reply *qr = + (struct of10::ofp_queue_get_config_reply *) buffer; + OFMsg::unpack(buffer); + this->port_ = ntoh16(qr->port); + uint8_t *p = buffer + sizeof(struct of10::ofp_queue_get_config_reply); + size_t len = this->length_ + - sizeof(struct of10::ofp_queue_get_config_reply); + while (len) { + PacketQueue pq; + pq.unpack(p); + this->queues_.push_back(pq); + p += pq.len(); + len -= pq.len(); + } + return 0; +} + +void QueueGetConfigReply::queues(std::list queues) { + this->queues_ = queues; + this->length_ += queues_len(); +} + +void QueueGetConfigReply::add_queue(PacketQueue queue) { + this->queues_.push_back(queue); + this->length_ += queue.len(); +} + +size_t QueueGetConfigReply::queues_len() { + size_t len; + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + len += it->len(); + } + return len; +} + +BarrierRequest::BarrierRequest() + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REQUEST) { +} + +BarrierRequest::BarrierRequest(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REQUEST, xid) { +} + +uint8_t* BarrierRequest::pack() { + return OFMsg::pack(); +} + +of_error BarrierRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + } + return 0; +} + +BarrierReply::BarrierReply() + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REPLY) { +} + +BarrierReply::BarrierReply(uint32_t xid) + : OFMsg(of10::OFP_VERSION, of10::OFPT_BARRIER_REPLY, xid) { +} + +uint8_t* BarrierReply::pack() { + return OFMsg::pack(); + +} + +of_error BarrierReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + return 0; +} + +} //End namespace of10. +} //End of namespace fluid_msg. diff --git a/src/ovs/libfluid-msg/of13/of13action.cc b/src/ovs/libfluid-msg/of13/of13action.cc new file mode 100644 index 00000000..0e79af12 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13action.cc @@ -0,0 +1,626 @@ +#include "libfluid-msg/of13/of13action.hh" + +namespace fluid_msg { + +namespace of13 { + +OutputAction::OutputAction() + : set_order_(230), + Action(of13::OFPAT_OUTPUT, sizeof(struct of13::ofp_action_output)) { +} + +bool OutputAction::equals(const Action &other) { + + if (const OutputAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->port_ == act->port_) + && (this->max_len_ == act->max_len_)); + } + else { + return false; + } +} + +OutputAction::OutputAction(uint32_t port, uint16_t max_len) + : set_order_(230), + Action(of13::OFPAT_OUTPUT, sizeof(struct of13::ofp_action_output)) { + this->port_ = port; + this->max_len_ = max_len; +} + +size_t OutputAction::pack(uint8_t* buffer) { + struct of13::ofp_action_output* ao = + (struct of13::ofp_action_output*) buffer; + Action::pack(buffer); + ao->port = hton32(this->port_); + ao->max_len = hton16(this->max_len_); + memset(ao->pad, 0x0, 6); + return 0; +} + +of_error OutputAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_output* ao = + (struct of13::ofp_action_output*) buffer; + Action::unpack(buffer); + this->port_ = ntoh32(ao->port); + this->max_len_ = ntoh16(ao->max_len); + return 0; +} + +CopyTTLInAction::CopyTTLInAction() + : set_order_(10), + Action(of13::OFPAT_COPY_TTL_IN, sizeof(struct ofp_action_header)) { +} + +size_t CopyTTLInAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error CopyTTLInAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +CopyTTLOutAction::CopyTTLOutAction() + : set_order_(110), + Action(of13::OFPAT_COPY_TTL_OUT, sizeof(struct ofp_action_header)) { +} + +size_t CopyTTLOutAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error CopyTTLOutAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +SetMPLSTTLAction::SetMPLSTTLAction() + : set_order_(140), + Action(of13::OFPAT_SET_MPLS_TTL, sizeof(struct of13::ofp_action_mpls_ttl)) { +} + +SetMPLSTTLAction::SetMPLSTTLAction(uint8_t mpls_ttl) + : set_order_(140), + Action(of13::OFPAT_SET_MPLS_TTL, sizeof(struct of13::ofp_action_mpls_ttl)) { + this->mpls_ttl_ = mpls_ttl; +} + +bool SetMPLSTTLAction::equals(const Action &other) { + + if (const SetMPLSTTLAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->mpls_ttl_ == act->mpls_ttl_)); + } + else { + return false; + } +} + +size_t SetMPLSTTLAction::pack(uint8_t* buffer) { + struct of13::ofp_action_mpls_ttl * mt = + (struct of13::ofp_action_mpls_ttl*) buffer; + Action::pack(buffer); + mt->mpls_ttl = this->mpls_ttl_; + memset(mt->pad, 0x0, 3); + return 0; +} + +of_error SetMPLSTTLAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_mpls_ttl * mt = + (struct of13::ofp_action_mpls_ttl*) buffer; + Action::unpack(buffer); + this->mpls_ttl_ = mt->mpls_ttl; + return 0; +} + +DecMPLSTTLAction::DecMPLSTTLAction() + : set_order_(120), + Action(of13::OFPAT_DEC_MPLS_TTL, sizeof(struct ofp_action_header)) { +} + +size_t DecMPLSTTLAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error DecMPLSTTLAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +PushVLANAction::PushVLANAction() + : set_order_(100), + Action(of13::OFPAT_PUSH_VLAN, sizeof(struct of13::ofp_action_push)) { +} + +PushVLANAction::PushVLANAction(uint16_t ethertype) + : set_order_(100), + Action(of13::OFPAT_PUSH_VLAN, sizeof(struct of13::ofp_action_push)) { + this->ethertype_ = ethertype; +} + +bool PushVLANAction::equals(const Action &other) { + + if (const PushVLANAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushVLANAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushVLANAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopVLANAction::PopVLANAction() + : set_order_(30), + Action(of13::OFPAT_POP_VLAN, sizeof(struct ofp_action_header)) { +} + +size_t PopVLANAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error PopVLANAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +PushMPLSAction::PushMPLSAction() + : set_order_(80), + Action(of13::OFPAT_PUSH_MPLS, sizeof(struct ofp_action_header)) { +} + +PushMPLSAction::PushMPLSAction(uint16_t ethertype) + : set_order_(80), + Action(of13::OFPAT_PUSH_MPLS, sizeof(struct ofp_action_header)) { + this->ethertype_ = ethertype; +} + +bool PushMPLSAction::equals(const Action &other) { + + if (const PushMPLSAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushMPLSAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushMPLSAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopMPLSAction::PopMPLSAction() + : set_order_(40), + Action(of13::OFPAT_POP_MPLS, sizeof(struct of13::ofp_action_pop_mpls)) { +} + +PopMPLSAction::PopMPLSAction(uint16_t ethertype) + : set_order_(40), + Action(of13::OFPAT_POP_MPLS, sizeof(struct of13::ofp_action_pop_mpls)) { + this->ethertype_ = ethertype; +} + +bool PopMPLSAction::equals(const Action &other) { + + if (const PopMPLSAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PopMPLSAction::pack(uint8_t* buffer) { + struct of13::ofp_action_pop_mpls *pm = + (struct of13::ofp_action_pop_mpls*) buffer; + Action::pack(buffer); + pm->ethertype = hton16(this->ethertype_); + memset(pm->pad, 0x0, 2); + return 0; +} + +of_error PopMPLSAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_pop_mpls *pm = + (struct of13::ofp_action_pop_mpls*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(pm->ethertype); + return 0; +} + +SetQueueAction::SetQueueAction() + : set_order_(170), + Action(of13::OFPAT_SET_QUEUE, sizeof(struct of13::ofp_action_set_queue)) { +} + +SetQueueAction::SetQueueAction(uint32_t queue_id) + : set_order_(170), + Action(of13::OFPAT_SET_QUEUE, sizeof(struct of13::ofp_action_set_queue)) { + this->queue_id_ = queue_id; +} + +bool SetQueueAction::equals(const Action &other) { + + if (const SetQueueAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->queue_id_ == act->queue_id_)); + } + else { + return false; + } +} + +size_t SetQueueAction::pack(uint8_t* buffer) { + struct of13::ofp_action_set_queue* aq = + (struct of13::ofp_action_set_queue*) buffer; + Action::pack(buffer); + aq->queue_id = hton32(this->queue_id_); + return 0; +} + +of_error SetQueueAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_set_queue* aq = + (struct of13::ofp_action_set_queue*) buffer; + Action::unpack(buffer); + this->queue_id_ = ntoh32(aq->queue_id); + return 0; +} + +GroupAction::GroupAction() + : set_order_(220), + Action(of13::OFPAT_GROUP, sizeof(struct of13::ofp_action_group)) { +} + +GroupAction::GroupAction(uint32_t group_id) + : set_order_(220), + Action(of13::OFPAT_GROUP, sizeof(struct of13::ofp_action_group)) { + this->group_id_ = group_id; +} + +bool GroupAction::equals(const Action &other) { + + if (const GroupAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->group_id_ == act->group_id_)); + } + else { + return false; + } +} + +size_t GroupAction::pack(uint8_t* buffer) { + struct of13::ofp_action_group *ag = (struct of13::ofp_action_group*) buffer; + Action::pack(buffer); + ag->group_id = hton32(this->group_id_); + return 0; +} + +of_error GroupAction::unpack(uint8_t *buffer) { + struct ofp_action_group *ag = (struct ofp_action_group*) buffer; + Action::unpack(buffer); + this->group_id_ = ntoh32(ag->group_id); + return 0; +} + +SetNWTTLAction::SetNWTTLAction() + : set_order_(150), + Action(of13::OFPAT_SET_NW_TTL, sizeof(struct of13::ofp_action_nw_ttl)) { +} + +SetNWTTLAction::SetNWTTLAction(uint8_t nw_ttl) + : set_order_(150), + Action(of13::OFPAT_SET_NW_TTL, sizeof(struct of13::ofp_action_nw_ttl)) { + this->nw_ttl_ = nw_ttl; +} + +bool SetNWTTLAction::equals(const Action &other) { + + if (const SetNWTTLAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->nw_ttl_ == act->nw_ttl_)); + } + else { + return false; + } +} + +size_t SetNWTTLAction::pack(uint8_t* buffer) { + struct of13::ofp_action_nw_ttl *nt = + (struct of13::ofp_action_nw_ttl*) buffer; + Action::pack(buffer); + nt->nw_ttl = this->nw_ttl_; + memset(nt->pad, 0x0, 3); + return 0; +} + +of_error SetNWTTLAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_nw_ttl *nt = + (struct of13::ofp_action_nw_ttl*) buffer; + Action::unpack(buffer); + this->nw_ttl_ = nt->nw_ttl; + return 0; +} + +DecNWTTLAction::DecNWTTLAction() + : set_order_(130), + Action(of13::OFPAT_DEC_NW_TTL, sizeof(struct ofp_action_header)) { +} + +size_t DecNWTTLAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error DecNWTTLAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +SetFieldAction::SetFieldAction() + : set_order_(160), + Action(of13::OFPAT_SET_FIELD, sizeof(struct of13::ofp_action_set_field)) { + +} + +SetFieldAction::SetFieldAction(OXMTLV* field) + : set_order_(160), + Action(of13::OFPAT_SET_FIELD, sizeof(struct of13::ofp_action_set_field)) { + this->field(field); +} + +SetFieldAction::SetFieldAction(const SetFieldAction &other) + : set_order_(160) { + this->type_ = other.type_; + this->length_ = other.length_; + this->field_ = other.field_->clone(); +} + +void SetFieldAction::field(OXMTLV* field) { + this->field_ = field; + this->length_ += ROUND_UP(field->length(), 8); +} + +SetFieldAction::~SetFieldAction() { + delete this->field_; +} + +void swap(SetFieldAction& first, SetFieldAction& second) { + std::swap(first.type_, second.type_); + std::swap(first.length_, second.length_); + std::swap(*(first.field_), *(second.field_)); +} + +SetFieldAction& SetFieldAction::operator=(SetFieldAction other) { + swap(*this, other); + return *this; +} + +bool SetFieldAction::equals(const Action &other) { + const SetFieldAction * action; + if (const SetFieldAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->field_->equals(*act->field_)) + && (this->length_ == act->length_)); + } + else { + return false; + } +} + +OXMTLV* SetFieldAction::field() { + return this->field_; +} + +size_t SetFieldAction::pack(uint8_t* buffer) { + size_t padding = ROUND_UP(this->field_->length(), 8) + - this->field_->length(); + Action::pack(buffer); + this->field_->pack( + buffer + (sizeof(struct of13::ofp_action_set_field) - 4)); + memset( + buffer + sizeof(struct of13::ofp_action_set_field) + + this->field_->length(), 0x0, padding); + return 0; +} + +of_error SetFieldAction::unpack(uint8_t *buffer) { + uint8_t * p = buffer + sizeof(struct of13::ofp_action_set_field) - 4; + size_t padding; + Action::unpack(buffer); + uint32_t header = ntoh32(*((uint32_t*) p)); + this->field_ = of13::Match::make_oxm_tlv(this->field_->oxm_field(header)); + this->field_->unpack(p); + return 0; +} + +PushPBBAction::PushPBBAction() + : set_order_(90), + Action(of13::OFPAT_PUSH_PBB, sizeof(struct of13::ofp_action_push)) { +} + +PushPBBAction::PushPBBAction(uint16_t ethertype) + : set_order_(90), + Action(of13::OFPAT_PUSH_PBB, sizeof(struct of13::ofp_action_push)) { + this->ethertype_ = ethertype; +} + +bool PushPBBAction::equals(const Action &other) { + + if (const PushPBBAction * act = dynamic_cast(&other)) { + return ((Action::equals(other)) && (this->ethertype_ == act->ethertype_)); + } + else { + return false; + } +} + +size_t PushPBBAction::pack(uint8_t* buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::pack(buffer); + ap->ethertype = hton16(this->ethertype_); + memset(ap->pad, 0x0, 2); + return 0; +} + +of_error PushPBBAction::unpack(uint8_t *buffer) { + struct of13::ofp_action_push *ap = (struct of13::ofp_action_push*) buffer; + Action::unpack(buffer); + this->ethertype_ = ntoh16(ap->ethertype); + return 0; +} + +PopPBBAction::PopPBBAction() + : set_order_(50), + Action(of13::OFPAT_POP_PBB, sizeof(struct of13::ofp_action_push)) { +} + +size_t PopPBBAction::pack(uint8_t* buffer) { + struct ofp_action_header * act = (struct ofp_action_header*) buffer; + Action::pack(buffer); + memset(act->pad, 0x0, 4); + return 0; +} + +of_error PopPBBAction::unpack(uint8_t *buffer) { + Action::unpack(buffer); + return 0; +} + +ExperimenterAction::ExperimenterAction() + : Action(of13::OFPAT_EXPERIMENTER, + sizeof(struct of13::ofp_action_experimenter_header)) { +} + +ExperimenterAction::ExperimenterAction(uint32_t experimenter) + : Action(of13::OFPAT_EXPERIMENTER, + sizeof(struct of13::ofp_action_experimenter_header)) { + this->experimenter_ = experimenter; +} + +bool ExperimenterAction::equals(const Action &other) { + + if (const ExperimenterAction * act = + dynamic_cast(&other)) { + return ((Action::equals(other)) + && (this->experimenter_ == act->experimenter_)); + } + else { + return false; + } +} + +size_t ExperimenterAction::pack(uint8_t* buffer) { + struct ofp_action_experimenter_header * ae = + (struct ofp_action_experimenter_header*) buffer; + Action::pack(buffer); + ae->experimenter = hton32(this->experimenter_); + return 0; +} + +of_error ExperimenterAction::unpack(uint8_t *buffer) { + struct ofp_action_experimenter_header * ae = + (struct ofp_action_experimenter_header*) buffer; + Action::unpack(buffer); + this->experimenter_ = ntoh32(ae->experimenter); + return 0; +} + +} //End of namespace of13 + +Action * Action::make_of13_action(uint16_t type) { + switch (type) { + case (of13::OFPAT_OUTPUT): { + return new of13::OutputAction(); + } + case (of13::OFPAT_COPY_TTL_OUT): { + return new of13::CopyTTLOutAction(); + } + case (of13::OFPAT_COPY_TTL_IN): { + return new of13::CopyTTLInAction(); + } + case (of13::OFPAT_SET_MPLS_TTL): { + return new of13::SetMPLSTTLAction(); + } + case (of13::OFPAT_DEC_MPLS_TTL): { + return new of13::DecMPLSTTLAction(); + } + case (of13::OFPAT_PUSH_VLAN): { + return new of13::PushVLANAction(); + } + case (of13::OFPAT_POP_VLAN): { + return new of13::PopVLANAction(); + } + case (of13::OFPAT_PUSH_MPLS): { + return new of13::PushMPLSAction(); + } + case (of13::OFPAT_POP_MPLS): { + return new of13::PopMPLSAction(); + } + case (of13::OFPAT_SET_QUEUE): { + return new of13::SetQueueAction(); + } + case (of13::OFPAT_GROUP): { + return new of13::GroupAction(); + } + case (of13::OFPAT_SET_NW_TTL): { + return new of13::SetNWTTLAction(); + } + case (of13::OFPAT_DEC_NW_TTL): { + return new of13::DecNWTTLAction(); + } + case (of13::OFPAT_SET_FIELD): { + return new of13::SetFieldAction(); + } + case (of13::OFPAT_PUSH_PBB): { + return new of13::PushPBBAction(); + } + case (of13::OFPAT_POP_PBB): { + return new of13::PopPBBAction(); + } + case (of13::OFPAT_EXPERIMENTER): { + return new of13::ExperimenterAction(); + } + } + return NULL; +} + +} //End of namespace fluid_msg + diff --git a/src/ovs/libfluid-msg/of13/of13common.cc b/src/ovs/libfluid-msg/of13/of13common.cc new file mode 100644 index 00000000..7a20f288 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13common.cc @@ -0,0 +1,1337 @@ +#include "libfluid-msg/of13/of13common.hh" + +namespace fluid_msg { + +namespace of13 { + +HelloElem::HelloElem(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool HelloElem::operator==(const HelloElem &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool HelloElem::operator!=(const HelloElem &other) const { + return !(*this == other); +} + +HelloElemVersionBitmap::HelloElemVersionBitmap(std::list bitmaps) + : HelloElem(of13::OFPHET_VERSIONBITMAP, + sizeof(struct of13::ofp_hello_elem_versionbitmap)) { + this->bitmaps_ = bitmaps; + this->length_ += bitmaps.size() * sizeof(uint32_t); +} + +bool HelloElemVersionBitmap::operator==( + const HelloElemVersionBitmap &other) const { + return ((HelloElem::operator==(other)) && (this->bitmaps_ == other.bitmaps_)); +} + +bool HelloElemVersionBitmap::operator!=( + const HelloElemVersionBitmap &other) const { + return !(*this == other); +} + +void HelloElemVersionBitmap::add_bitmap(uint32_t bitmap) { + this->bitmaps_.push_back(bitmap); + this->length_ += sizeof(uint32_t); +} + +size_t HelloElemVersionBitmap::pack(uint8_t* buffer) { + struct of13::ofp_hello_elem_versionbitmap *elem = + (struct of13::ofp_hello_elem_versionbitmap *) buffer; + elem->type = hton16(this->type_); + elem->length = hton16(this->length_); + uint8_t *p = buffer + sizeof(struct of13::ofp_hello_elem_versionbitmap); + for (std::list::iterator it = this->bitmaps_.begin(); + it != this->bitmaps_.end(); it++) { + uint32_t bitmap = hton32(*it); + memcpy(p, &bitmap, sizeof(uint32_t)); + p += sizeof(uint32_t); + } + return 0; +} + +of_error HelloElemVersionBitmap::unpack(uint8_t* buffer) { + struct of13::ofp_hello_elem_versionbitmap *elem = + (struct of13::ofp_hello_elem_versionbitmap *) buffer; + this->type_ = ntoh16(elem->type); + this->length_ = ntoh16(elem->length); + uint32_t bitmaps; + memcpy(&bitmaps, elem->bitmaps, sizeof(uint32_t)); + uint8_t *p = buffer + sizeof(struct of13::ofp_hello_elem_versionbitmap); + size_t len = this->length_ + - sizeof(struct of13::ofp_hello_elem_versionbitmap); + while (len) { + uint32_t bitmap = ntoh32((*(uint32_t*) p)); + this->bitmaps_.push_back(bitmap); + p += sizeof(uint32_t); + len -= sizeof(uint32_t); + } + return 0; +} + +Port::Port() + : PortCommon(), + port_no_(0), + curr_speed_(0), + max_speed_(0) { +} + +Port::Port(uint32_t port_no, EthAddress hw_addr, std::string name, + uint32_t config, uint32_t state, uint32_t curr, uint32_t advertised, + uint32_t supported, uint32_t peer, uint32_t curr_speed, uint32_t max_speed) + : PortCommon(hw_addr, name, config, state, curr, advertised, supported, + peer), + port_no_(port_no), + curr_speed_(curr_speed), + max_speed_(max_speed) { +} + +bool Port::operator==(const Port &other) const { + return ((PortCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->curr_speed_ == other.curr_speed_) + && (this->max_speed_ == other.max_speed_)); +} + +bool Port::operator!=(const Port &other) const { + return !(*this == other); +} + +size_t Port::pack(uint8_t* buffer) { + struct of13::ofp_port *port = (struct of13::ofp_port*) buffer; + port->port_no = hton32(this->port_no_); + memset(port->pad, 0x0, 4); + memcpy(port->hw_addr, this->hw_addr_.get_data(), OFP_ETH_ALEN); + memset(port->pad2, 0x0, 2); + memset(port->name, 0x0, OFP_MAX_PORT_NAME_LEN); + memcpy(port->name, this->name_.c_str(), + this->name_.size() < OFP_MAX_PORT_NAME_LEN ? + this->name_.size() : OFP_MAX_PORT_NAME_LEN); + port->config = hton32(this->config_); + port->state = hton32(this->state_); + port->curr = hton32(this->curr_); + port->advertised = hton32(this->advertised_); + port->supported = hton32(this->supported_); + port->peer = hton32(this->peer_); + port->curr_speed = hton32(this->curr_speed_); + port->max_speed = hton32(this->max_speed_); + return 0; +} + +of_error Port::unpack(uint8_t* buffer) { + struct of13::ofp_port *port = (struct of13::ofp_port*) buffer; + this->port_no_ = ntoh32(port->port_no); + this->hw_addr_ = EthAddress(port->hw_addr); + this->name_ = std::string(port->name); + this->config_ = ntoh32(port->config); + this->state_ = ntoh32(port->state); + this->curr_ = ntoh32(port->curr); + this->advertised_ = ntoh32(port->advertised); + this->supported_ = ntoh32(port->supported); + this->peer_ = ntoh32(port->peer); + this->curr_speed_ = ntoh32(port->curr_speed); + this->max_speed_ = ntoh32(port->max_speed); + return 0; +} + +QueuePropMinRate::QueuePropMinRate(uint16_t rate) + : QueuePropRate(of13::OFPQT_MIN_RATE, rate) { + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +bool QueuePropMinRate::equals(const QueueProperty &other) { + if (const QueuePropMinRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMinRate::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMinRate::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +QueuePropMaxRate::QueuePropMaxRate(uint16_t rate) + : QueuePropRate(of13::OFPQT_MAX_RATE, rate) { + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +bool QueuePropMaxRate::equals(const QueueProperty &other) { + if (const QueuePropMaxRate * prop = + dynamic_cast(&other)) { + return ((QueuePropRate::equals(other))); + } + else { + return false; + } +} + +size_t QueuePropMaxRate::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::pack(buffer); + qp->rate = hton16(this->rate_); + memset(qp->pad, 0x0, 6); + return this->len_; +} + +of_error QueuePropMaxRate::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_min_rate *qp = + (struct of13::ofp_queue_prop_min_rate *) buffer; + QueueProperty::unpack(buffer); + this->rate_ = ntoh16(qp->rate); + return 0; +} + +QueueExperimenter::QueueExperimenter(uint32_t experimenter) + : QueueProperty(of13::OFPQT_EXPERIMENTER) { + this->experimenter_ = experimenter; + this->len_ = sizeof(struct of13::ofp_queue_prop_min_rate); +} + +size_t QueueExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_queue_prop_experimenter *qp = + (struct of13::ofp_queue_prop_experimenter *) buffer; + QueueProperty::pack(buffer); + qp->experimenter = hton32(this->experimenter_); + memset(qp->pad, 0x0, 4); + return this->len_; +} + +of_error QueueExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_queue_prop_experimenter *qp = + (struct of13::ofp_queue_prop_experimenter *) buffer; + QueueProperty::unpack(buffer); + this->experimenter_ = ntoh32(qp->experimenter); + return 0; +} + +PacketQueue::PacketQueue() + : PacketQueueCommon(), + port_(0) { + this->len_ = sizeof(struct of13::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, uint32_t port) + : PacketQueueCommon(queue_id) { + this->port_ = port; + this->len_ = sizeof(struct of13::ofp_packet_queue); +} + +PacketQueue::PacketQueue(uint32_t queue_id, uint32_t port, + QueuePropertyList properties) + : PacketQueueCommon(queue_id) { + this->port_ = port; + this->properties_ = properties; + this->len_ = sizeof(struct of13::ofp_packet_queue) + properties.length(); +} + +bool PacketQueue::operator==(const PacketQueue &other) const { + return ((PacketQueueCommon::operator==(other)) + && (this->port_ == other.port_)); +} + +bool PacketQueue::operator!=(const PacketQueue &other) const { + return !(*this == other); +} + +size_t PacketQueue::pack(uint8_t* buffer) { + struct of13::ofp_packet_queue *pq = (struct of13::ofp_packet_queue*) buffer; + pq->queue_id = hton32(this->queue_id_); + pq->port = hton32(this->port_); + pq->len = hton16(this->len_); + memset(pq->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_queue); + this->properties_.pack(p); + return this->len_; +} + +of_error PacketQueue::unpack(uint8_t* buffer) { + struct of13::ofp_packet_queue *pq = (struct of13::ofp_packet_queue*) buffer; + this->queue_id_ = ntoh32(pq->queue_id); + this->port_ = ntoh32(pq->port); + this->len_ = ntoh16(pq->len); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_queue); + this->properties_.length( + this->len_ - sizeof(struct of13::ofp_packet_queue)); + this->properties_.unpack13(p); + return 0; +} + +Bucket::Bucket() + : length_(sizeof(struct of13::ofp_bucket)), + weight_(0), + watch_port_(0), + watch_group_(0) { +} + +Bucket::Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group) { + this->weight_ = weight; + this->watch_port_ = watch_port; + this->watch_group_ = watch_group; + this->length_ = sizeof(struct of13::ofp_bucket); +} + +Bucket::Bucket(uint16_t weight, uint32_t watch_port, uint32_t watch_group, + ActionSet actions) { + this->weight_ = weight; + this->watch_port_ = watch_port; + this->watch_group_ = watch_group; + this->actions_ = actions; + this->length_ = sizeof(struct of13::ofp_bucket) + actions.length(); +} + +bool Bucket::operator==(const Bucket &other) const { + return ((this->length_ == other.length_) && (this->weight_ == other.weight_) + && (this->watch_port_ == other.watch_port_) + && (this->watch_group_ == other.watch_group_) + && (this->actions_ == other.actions_)); +} + +bool Bucket::operator!=(const Bucket &other) const { + return !(*this == other); +} + +void Bucket::actions(ActionSet actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void Bucket::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void Bucket::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t Bucket::pack(uint8_t* buffer) { + struct of13::ofp_bucket *b = (struct of13::ofp_bucket*) buffer; + b->len = hton16(this->length_); + b->weight = hton16(this->weight_); + b->watch_port = hton32(this->watch_port_); + b->watch_group = hton32(this->watch_group_); + memset(b->pad, 0x0, 4); + this->actions_.pack(buffer + sizeof(struct of13::ofp_bucket)); + return 0; +} + +of_error Bucket::unpack(uint8_t* buffer) { + struct of13::ofp_bucket *b = (struct of13::ofp_bucket*) buffer; + this->length_ = ntoh16(b->len); + this->weight_ = ntoh16(b->weight); + this->watch_port_ = ntoh32(b->watch_port); + this->watch_group_ = ntoh32(b->watch_group); + this->actions_.length(this->length_ - sizeof(struct of13::ofp_bucket)); + this->actions_.unpack(buffer + sizeof(struct of13::ofp_bucket)); + return 0; +} + +FlowStats::FlowStats() + : FlowStatsCommon(), + flags_(0) { + this->length_ = sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match); +} + +FlowStats::FlowStats(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t flags, uint64_t cookie, + uint64_t packet_count, uint64_t byte_count) + : FlowStatsCommon(table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, byte_count) { + this->flags_ = flags; + this->length_ = sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match); +} + +bool FlowStats::operator==(const FlowStats &other) const { + return ((FlowStatsCommon::operator==(other)) + && (this->flags_ == other.flags_) + && (this->instructions_ == other.instructions_) + && (this->match_ == other.match_)); +} + +bool FlowStats::operator!=(const FlowStats &other) const { + return !(*this == other); +} + +size_t FlowStats::pack(uint8_t* buffer) { + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_flow_stats) - sizeof(struct of13::ofp_match) + + this->match_.length(), 8) + - (sizeof(struct of13::ofp_flow_stats) - sizeof(struct of13::ofp_match) + + this->match_.length()); + struct of13::ofp_flow_stats *fs = (struct of13::ofp_flow_stats*) buffer; + fs->length = hton16(this->length_); + fs->table_id = this->table_id_; + memset(&fs->pad, 0x0, 1); + fs->duration_sec = hton32(this->duration_sec_); + fs->duration_nsec = hton32(this->duration_nsec_); + fs->priority = hton16(this->priority_); + fs->idle_timeout = hton16(this->idle_timeout_); + fs->hard_timeout = hton16(this->hard_timeout_); + fs->flags = hton16(this->flags_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->packet_count = hton64(this->packet_count_); + fs->byte_count = hton64(this->byte_count_); + uint8_t *p = + buffer + + (sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + p += padding; + this->instructions_.pack(p); + return this->length_; +} + +of_error FlowStats::unpack(uint8_t* buffer) { + struct of13::ofp_flow_stats *fs = (struct of13::ofp_flow_stats*) buffer; + this->length_ = ntoh16(fs->length); + this->table_id_ = fs->table_id; + this->duration_sec_ = ntoh32(fs->duration_sec); + this->duration_nsec_ = ntoh32(fs->duration_nsec); + this->priority_ = ntoh16(fs->priority); + this->idle_timeout_ = ntoh16(fs->idle_timeout); + this->hard_timeout_ = ntoh16(fs->hard_timeout); + this->flags_ = ntoh16(fs->flags); + this->cookie_ = ntoh64(fs->cookie); + this->packet_count_ = ntoh64(fs->packet_count); + this->byte_count_ = ntoh64(fs->byte_count); + uint8_t *p = + buffer + + (sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + this->instructions_.length( + this->length_ + - ((sizeof(struct of13::ofp_flow_stats) + - sizeof(struct of13::ofp_match)) + + ROUND_UP(this->match_.length(), 8))); + p += ROUND_UP(this->match_.length(), 8); + this->instructions_.unpack(p); + return 0; +} + +void FlowStats::match(of13::Match match) { + this->match_ = match; + this->length_ += match.length(); + //Padding bytes + this->length_ = ROUND_UP(this->length_, 8); +} + +OXMTLV * FlowStats::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void FlowStats::instructions(InstructionSet instructions) { + this->instructions_ = instructions; + this->length_ += instructions.length(); +} + +void FlowStats::add_instruction(Instruction* inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst->length(); +} + +TableStats::TableStats() + : TableStatsCommon() { +} + +TableStats::TableStats(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count) + : TableStatsCommon(table_id, active_count, lookup_count, matched_count) { +} + +size_t TableStats::pack(uint8_t* buffer) { + struct of13::ofp_table_stats *ts = (struct of13::ofp_table_stats*) buffer; + ts->table_id = this->table_id_; + memset(ts->pad, 0x0, 3); + ts->active_count = hton32(this->active_count_); + ts->lookup_count = hton64(this->lookup_count_); + ts->matched_count = hton64(this->matched_count_); + return 0; +} + +of_error TableStats::unpack(uint8_t* buffer) { + struct of13::ofp_table_stats *ts = (struct of13::ofp_table_stats*) buffer; + this->table_id_ = ts->table_id; + this->active_count_ = ntoh32(ts->active_count); + this->lookup_count_ = ntoh64(ts->lookup_count); + this->matched_count_ = ntoh64(ts->matched_count); + return 0; +} + +PortStats::PortStats() + : PortStatsCommon(), + port_no_(0), + duration_sec_(0), + duration_nsec_(0) { +} + +PortStats::PortStats(uint32_t port_no, struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions, uint32_t duration_sec, + uint32_t duration_nsec) + : PortStatsCommon(rx_tx_stats, err_stats, collisions) { + this->port_no_ = port_no; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; +} + +bool PortStats::operator==(const PortStats &other) const { + return ((PortStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} + +bool PortStats::operator!=(const PortStats &other) const { + return !(*this == other); +} + +size_t PortStats::pack(uint8_t* buffer) { + struct of13::ofp_port_stats *ps = (struct of13::ofp_port_stats*) buffer; + ps->port_no = hton32(this->port_no_); + memset(ps->pad, 0x0, 6); + PortStatsCommon::pack(buffer + 8); + ps->collisions = hton64(this->collisions_); + ps->duration_sec = hton32(this->duration_sec_); + ps->duration_nsec = hton32(this->duration_nsec_); + return 0; +} + +of_error PortStats::unpack(uint8_t* buffer) { + struct of13::ofp_port_stats *ps = (struct of13::ofp_port_stats*) buffer; + this->port_no_ = ntoh32(ps->port_no); + PortStatsCommon::unpack(buffer + 8); + this->collisions_ = ntoh64(ps->collisions); + this->duration_sec_ = hton32(ps->duration_sec); + this->duration_nsec_ = hton32(ps->duration_nsec); + return 0; +} + +QueueStats::QueueStats() + : QueueStatsCommon(), + port_no_(0), + duration_sec_(0), + duration_nsec_(0) { + +} + +QueueStats::QueueStats(uint32_t port_no, uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors, uint32_t duration_sec, + uint32_t duration_nsec) + : QueueStatsCommon(queue_id, tx_bytes, tx_packets, tx_errors) { + this->port_no_ = port_no; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; +} + +bool QueueStats::operator==(const QueueStats &other) const { + return ((QueueStatsCommon::operator==(other)) + && (this->port_no_ == other.port_no_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} +bool QueueStats::operator!=(const QueueStats &other) const { + return !(*this == other); +} + +size_t QueueStats::pack(uint8_t* buffer) { + struct of13::ofp_queue_stats *qs = (struct of13::ofp_queue_stats*) buffer; + qs->port_no = hton32(this->port_no_); + qs->queue_id = hton32(this->queue_id_); + qs->tx_bytes = hton64(this->tx_bytes_); + qs->tx_packets = hton64(this->tx_packets_); + qs->tx_errors = hton64(this->tx_errors_); + qs->duration_sec = hton32(this->duration_sec_); + qs->duration_nsec = hton32(this->duration_nsec_); + return 0; +} + +of_error QueueStats::unpack(uint8_t* buffer) { + struct of13::ofp_queue_stats *qs = (struct of13::ofp_queue_stats*) buffer; + this->port_no_ = ntoh32(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + this->tx_bytes_ = ntoh64(qs->tx_bytes); + this->tx_packets_ = ntoh64(qs->tx_packets); + this->tx_errors_ = ntoh64(qs->tx_errors); + this->duration_sec_ = ntoh32(qs->duration_sec); + this->duration_nsec_ = ntoh32(qs->duration_nsec); + return 0; +} + +BucketStats::BucketStats() + : packet_count_(0), + byte_count_(0) { + +} + +BucketStats::BucketStats(uint64_t packet_count, uint64_t byte_count) { + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; +} + +bool BucketStats::operator==(const BucketStats &other) const { + return ((this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool BucketStats::operator!=(const BucketStats &other) const { + return !(*this == other); +} + +size_t BucketStats::pack(uint8_t* buffer) { + struct of13::ofp_bucket_counter *bc = + (struct of13::ofp_bucket_counter *) buffer; + bc->packet_count = hton64(this->packet_count_); + bc->byte_count = hton64(this->byte_count_); + return 0; +} + +of_error BucketStats::unpack(uint8_t* buffer) { + struct of13::ofp_bucket_counter *bc = + (struct of13::ofp_bucket_counter *) buffer; + this->packet_count_ = ntoh64(bc->packet_count); + this->byte_count_ = ntoh64(bc->byte_count); + return 0; +} + +GroupStats::GroupStats(uint32_t group_id, uint32_t ref_count, + uint64_t packet_count, uint64_t byte_count, uint32_t duration_sec, + uint32_t duration_nsec) { + this->group_id_ = group_id; + this->ref_count_ = ref_count; + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->length_ = sizeof(struct of13::ofp_group_stats); +} + +GroupStats::GroupStats(uint32_t group_id, uint32_t ref_count, + uint64_t packet_count, uint64_t byte_count, uint32_t duration_sec, + uint32_t duration_nsec, std::vector bucket_stats) { + this->group_id_ = group_id; + this->ref_count_ = ref_count; + this->packet_count_ = packet_count; + this->byte_count_ = byte_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->bucket_stats_ = bucket_stats; + this->length_ = sizeof(struct of13::ofp_group_stats) + + bucket_stats.size() * sizeof(struct of13::ofp_bucket_counter); +} + +bool GroupStats::operator==(const GroupStats &other) const { + return ((this->group_id_ == other.group_id_) + && (this->ref_count_ == other.ref_count_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->bucket_stats_ == other.bucket_stats_) + && (this->length_ == other.length_)); +} + +bool GroupStats::operator!=(const GroupStats &other) const { + return !(*this == other); +} + +size_t GroupStats::pack(uint8_t* buffer) { + struct of13::ofp_group_stats *gs = (struct of13::ofp_group_stats *) buffer; + gs->length = hton16(this->length_); + gs->group_id = hton32(this->group_id_); + gs->ref_count = hton32(this->ref_count_); + gs->packet_count = hton64(this->packet_count_); + gs->byte_count = hton64(this->byte_count_); + gs->duration_sec = hton32(this->duration_sec_); + gs->duration_nsec = hton32(this->duration_nsec_); + uint8_t *p = buffer + sizeof(of13::ofp_group_stats); + for (std::vector::iterator it = this->bucket_stats_.begin(); + it != this->bucket_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_bucket_counter); + } + return 0; +} + +of_error GroupStats::unpack(uint8_t* buffer) { + struct of13::ofp_group_stats *gs = (struct of13::ofp_group_stats *) buffer; + this->length_ = ntoh16(gs->length); + this->group_id_ = ntoh32(gs->group_id); + this->ref_count_ = ntoh32(gs->ref_count); + this->packet_count_ = ntoh64(gs->packet_count); + this->byte_count_ = ntoh64(gs->byte_count); + this->duration_sec_ = ntoh32(gs->duration_sec); + this->duration_nsec_ = ntoh32(gs->duration_nsec); + uint8_t *p = buffer + sizeof(of13::ofp_group_stats); + size_t len = this->length_ - sizeof(of13::ofp_group_stats); + while (len) { + BucketStats stats; + stats.unpack(p); + this->bucket_stats_.push_back(stats); + p += sizeof(struct of13::ofp_bucket_counter); + len -= sizeof(struct of13::ofp_bucket_counter); + } + return 0; +} + +void GroupStats::bucket_stats(std::vector bucket_stats) { + this->bucket_stats_ = bucket_stats; + this->length_ += bucket_stats.size() + * sizeof(struct of13::ofp_bucket_counter); +} +void GroupStats::add_bucket_stat(BucketStats stat) { + this->bucket_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_bucket_counter); +} + +GroupDesc::GroupDesc(uint8_t type, uint32_t group_id) { + this->type_ = type; + this->group_id_ = group_id; + this->length_ = sizeof(struct of13::ofp_group_desc_stats); +} + +GroupDesc::GroupDesc(uint8_t type, uint32_t group_id, + std::vector buckets) { + this->type_ = type; + this->group_id_ = group_id; + this->buckets_ = buckets; + this->length_ = sizeof(struct of13::ofp_group_desc_stats) + buckets_len(); +} + +bool GroupDesc::operator==(const GroupDesc &other) const { + return ((this->type_ == other.type_) && (this->group_id_ == other.group_id_) + && (this->length_ == other.length_) + && (this->buckets_ == other.buckets_)); +} + +bool GroupDesc::operator!=(const GroupDesc &other) const { + return !(*this == other); +} + +size_t GroupDesc::pack(uint8_t* buffer) { + struct of13::ofp_group_desc_stats * gd = + (struct of13::ofp_group_desc_stats *) buffer; + gd->length = hton16(this->length_); + gd->type = this->type_; + memset(&gd->pad, 0x0, 1); + gd->group_id = hton32(this->group_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_group_desc_stats); + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return this->length_; +} + +of_error GroupDesc::unpack(uint8_t* buffer) { + struct of13::ofp_group_desc_stats * gd = + (struct of13::ofp_group_desc_stats *) buffer; + this->length_ = ntoh16(gd->length); + this->type_ = gd->type; + this->group_id_ = ntoh32(gd->group_id); + size_t len = this->length_ - sizeof(struct of13::ofp_group_desc_stats); + uint8_t *p = buffer + sizeof(struct of13::ofp_group_desc_stats); + while (len) { + Bucket bucket; + bucket.unpack(p); + this->buckets_.push_back(bucket); + p += bucket.len(); + len -= bucket.len(); + } + return 0; +} + +void GroupDesc::buckets(std::vector buckets) { + this->buckets_ = buckets; + this->length_ += buckets_len(); +} + +void GroupDesc::add_bucket(Bucket bucket) { + this->buckets_.push_back(bucket); + this->length_ += bucket.len(); +} + +size_t GroupDesc::buckets_len() { + size_t len = 0; + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + len += it->len(); + } + return len; +} +; + +GroupFeatures::GroupFeatures(uint32_t types, uint32_t capabilities, + uint32_t max_groups[4], uint32_t actions[4]) { + this->types_ = types; + this->capabilities_ = capabilities; + memcpy(this->max_groups_, max_groups, 16); + memcpy(this->actions_, actions, 16); +} + +bool GroupFeatures::operator==(const GroupFeatures &other) const { + for (int i = 0; i < 4; i++) { + if (this->max_groups_[i] != other.max_groups_[i]) { + return false; + } + if (this->actions_[i] != other.actions_[i]) { + return false; + } + } + return ((this->types_ == other.types_) + && (this->capabilities_ == other.capabilities_)); +} + +bool GroupFeatures::operator!=(const GroupFeatures &other) const { + return !(*this == other); +} + +size_t GroupFeatures::pack(uint8_t* buffer) { + struct of13::ofp_group_features *gf = + (struct of13::ofp_group_features*) buffer; + gf->types = hton32(this->types_); + gf->capabilities = hton32(this->capabilities_); + for (int i = 0; i < 4; i++) { + gf->max_groups[i] = hton32(this->max_groups_[i]); + gf->actions[i] = hton32(this->actions_[i]); + } + return 0; +} + +of_error GroupFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_group_features *gf = + (struct of13::ofp_group_features*) buffer; + this->types_ = ntoh32(gf->types); + this->capabilities_ = ntoh32(gf->capabilities); + for (int i = 0; i < 4; i++) { + this->max_groups_[i] = ntoh32(gf->max_groups[i]); + this->actions_[i] = ntoh32(gf->actions[i]); + } + return 0; +} + +TableFeatureProp::TableFeatureProp(uint16_t type) { + this->type_ = type; + this->length_ = sizeof(struct of13::ofp_table_feature_prop_header); + this->padding_ = ROUND_UP( + sizeof(struct of13::ofp_table_feature_prop_header), 8) + - sizeof(struct of13::ofp_table_feature_prop_header); +} + +bool TableFeatureProp::equals(const TableFeatureProp &other) { + return ((*this == other)); +} + +bool TableFeatureProp::operator==(const TableFeatureProp &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool TableFeatureProp::operator!=(const TableFeatureProp &other) const { + return !(*this == other); +} + +size_t TableFeatureProp::pack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_header *fp = + (struct of13::ofp_table_feature_prop_header*) buffer; + fp->type = hton16(this->type_); + fp->length = hton16(this->length_); + return 0; +} + +of_error TableFeatureProp::unpack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_header *fp = + (struct of13::ofp_table_feature_prop_header*) buffer; + this->type_ = ntoh16(fp->type); + this->length_ = ntoh16(fp->length); + return 0; +} + +TableFeaturePropInstruction::TableFeaturePropInstruction(uint16_t type, + std::vector instruction_ids) + : TableFeatureProp(type) { + this->instruction_ids_ = instruction_ids; + this->length_ += instruction_ids.size() + * sizeof(struct of13::ofp_instruction); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropInstruction::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropInstruction * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->instruction_ids_ == prop->instruction_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropInstruction::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->instruction_ids_.begin(); + it != this->instruction_ids_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_instruction); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropInstruction::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + Instruction inst; + while (len) { + inst.unpack(p); + this->instruction_ids_.push_back(inst); + p += sizeof(struct of13::ofp_instruction); + len -= sizeof(struct of13::ofp_instruction); + } + return 0; +} + +void TableFeaturePropInstruction::instruction_ids( + std::vector instruction_ids) { + this->instruction_ids_ = instruction_ids; + //Total length with padding + this->length_ += instruction_ids.size() + * sizeof(struct of13::ofp_instruction); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropNextTables::TableFeaturePropNextTables(uint16_t type, + std::vector next_table_ids) + : TableFeatureProp(type) { + this->next_table_ids_ = next_table_ids_; + this->length_ += next_table_ids_.size(); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropNextTables::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropNextTables * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->next_table_ids_ == prop->next_table_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropNextTables::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->next_table_ids_.begin(); + it != this->next_table_ids_.end(); ++it) { + memcpy(p, &(*it), sizeof(uint8_t)); + p += sizeof(uint8_t); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropNextTables::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + while (len) { + this->next_table_ids_.push_back(*p); + p += sizeof(uint8_t); + len -= sizeof(uint8_t); + } + return 0; +} + +void TableFeaturePropNextTables::table_ids( + std::vector next_table_ids) { + this->next_table_ids_ = next_table_ids; + this->length_ += next_table_ids_.size() * sizeof(uint8_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropActions::TableFeaturePropActions(uint16_t type, + std::vector action_ids) + : TableFeatureProp(type) { + this->action_ids_ = action_ids; + this->length_ += action_ids.size() * sizeof(struct ofp_action_header); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropActions::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropActions * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->action_ids_ == prop->action_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropActions::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->action_ids_.begin(); + it != this->action_ids_.end(); ++it) { + it->pack(p); + p += sizeof(struct ofp_action_header); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropActions::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + Action act; + while (len) { + act.unpack(p); + this->action_ids_.push_back(act); + p += sizeof(struct ofp_action_header); + len -= sizeof(struct ofp_action_header); + } + return 0; +} + +void TableFeaturePropActions::action_ids(std::vector action_ids) { + this->action_ids_ = action_ids; + this->length_ += action_ids.size() * sizeof(struct ofp_action_header); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropOXM::TableFeaturePropOXM(uint16_t type, + std::vector oxm_ids) + : TableFeatureProp(type) { + this->oxm_ids_ = oxm_ids; + this->length_ += oxm_ids_.size() * sizeof(uint32_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +bool TableFeaturePropOXM::equals(const TableFeatureProp &other) { + if (const TableFeaturePropOXM * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->oxm_ids_ == prop->oxm_ids_)); + } + else { + return false; + } +} + +size_t TableFeaturePropOXM::pack(uint8_t* buffer) { + TableFeatureProp::pack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + for (std::vector::iterator it = this->oxm_ids_.begin(); + it != this->oxm_ids_.end(); ++it) { + memcpy(p, &(*it), sizeof(uint32_t)); + p += sizeof(uint32_t); + } + memset(p, 0x0, this->padding_); + return 0; +} + +of_error TableFeaturePropOXM::unpack(uint8_t* buffer) { + TableFeatureProp::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_feature_prop_header); + size_t len = this->length_ + - sizeof(struct of13::ofp_table_feature_prop_header); + while (len) { + uint32_t *oxm_id = (uint32_t*) p; + this->oxm_ids_.push_back(*oxm_id); + p += sizeof(uint32_t); + len -= sizeof(uint32_t); + } + return 0; +} + +void TableFeaturePropOXM::oxm_ids(std::vector oxm_ids) { + this->oxm_ids_ = oxm_ids; + this->length_ += oxm_ids_.size() * sizeof(uint32_t); + this->padding_ = ROUND_UP(this->length_, 8) - this->length_; +} + +TableFeaturePropExperimenter::TableFeaturePropExperimenter(uint16_t type, + uint32_t experimenter, uint32_t exp_type) + : TableFeatureProp(type) { + this->experimenter_ = experimenter; + this->exp_type_ = exp_type; + this->length_ += sizeof(struct of13::ofp_table_feature_prop_experimenter); +} + +bool TableFeaturePropExperimenter::equals(const TableFeatureProp &other) { + + if (const TableFeaturePropExperimenter * prop = + dynamic_cast(&other)) { + return ((TableFeatureProp::equals(other)) + && (this->experimenter_ == prop->experimenter_) + && (this->exp_type_ == prop->exp_type_)); + } + else { + return false; + } +} + +size_t TableFeaturePropExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_experimenter *pe = + (struct of13::ofp_table_feature_prop_experimenter*) buffer; + TableFeatureProp::pack(buffer); + pe->experimenter = hton32(this->experimenter_); + pe->exp_type = hton32(this->exp_type_); + return 0; +} + +of_error TableFeaturePropExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_table_feature_prop_experimenter *pe = + (struct of13::ofp_table_feature_prop_experimenter*) buffer; + TableFeatureProp::unpack(buffer); + this->experimenter_ = ntoh32(pe->experimenter); + this->exp_type_ = ntoh32(pe->exp_type); + return 0; +} + +TablePropertiesList::TablePropertiesList( + std::list property_list) { + this->property_list_ = property_list_; + for (std::list::const_iterator it = + property_list.begin(); it != property_list.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +TablePropertiesList::TablePropertiesList(const TablePropertiesList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = + other.property_list_.begin(); it != other.property_list_.end(); ++it) { + this->property_list_.push_back((*it)->clone()); + } +} + +TablePropertiesList::~TablePropertiesList() { + this->property_list_.remove_if(TableFeatureProp::delete_all); +} + +bool TablePropertiesList::operator==(const TablePropertiesList &other) const { + std::list::const_iterator ot = + other.property_list_.begin(); + for (std::list::const_iterator it = + this->property_list_.begin(); it != this->property_list_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool TablePropertiesList::operator!=(const TablePropertiesList &other) const { + return !(*this == other); +} + +size_t TablePropertiesList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = + this->property_list_.begin(), end = this->property_list_.end(); + it != end; it++) { + (*it)->pack(p); + p += (*it)->length() + (*it)->padding(); + } + return 0; +} + +of_error TablePropertiesList::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + TableFeatureProp *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = TableFeatures::make_table_feature_prop(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->length() + prop->padding(); + p += prop->length() + prop->padding(); + } + return 0; +} + +TablePropertiesList& TablePropertiesList::operator=(TablePropertiesList other) { + swap(*this, other); + return *this; +} + +void swap(TablePropertiesList& first, TablePropertiesList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.property_list_, second.property_list_); +} + +void TablePropertiesList::property_list( + std::list property_list) { + this->property_list_ = property_list; + for (std::list::const_iterator it = + property_list.begin(); it != property_list.end(); ++it) { + this->length_ += (*it)->length() + (*it)->padding(); + } +} + +void TablePropertiesList::add_property(TableFeatureProp* prop) { + this->property_list_.push_back(prop); + this->length_ = prop->length() + prop->padding(); +} + +TableFeatures::TableFeatures(uint8_t table_id, std::string name, + uint64_t metadata_match, uint64_t metadata_write, uint32_t config, + uint32_t max_entries) + : table_id_(table_id), + name_(name), + metadata_match_(metadata_match), + metadata_write_(metadata_write), + config_(config), + max_entries_(max_entries) { + this->length_ = sizeof(struct of13::ofp_table_features); +} + +bool TableFeatures::operator==(const TableFeatures &other) const { + return ((this->length_ == other.length_) + && (this->table_id_ == other.table_id_) && (this->name_ == other.name_) + && (this->metadata_match_ == other.metadata_match_) + && (this->metadata_write_ == other.metadata_write_) + && (this->config_ == other.config_) + && (this->max_entries_ == other.max_entries_) + && (this->properties_ == other.properties_)); +} + +bool TableFeatures::operator!=(const TableFeatures &other) const { + return !(*this == other); +} + +uint16_t TableFeatures::length() { + //Return padded len + return ROUND_UP(this->length_, 8); +} + +size_t TableFeatures::pack(uint8_t* buffer) { + struct of13::ofp_table_features *tf = + (struct of13::ofp_table_features*) buffer; + tf->length = hton16(length()); + tf->table_id = this->table_id_; + memset(tf->pad, 0x0, 5); + memset(tf->name, 0x0, OFP_FLUID_MAX_TABLE_NAME_LEN); + memcpy(tf->name, this->name_.c_str(), + this->name_.size() < OFP_FLUID_MAX_TABLE_NAME_LEN ? + this->name_.size() : OFP_FLUID_MAX_TABLE_NAME_LEN); + tf->metadata_match = hton64(this->metadata_match_); + tf->metadata_write = hton64(this->metadata_write_); + tf->config = hton32(this->config_); + tf->max_entries = hton32(this->max_entries_); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_features); + this->properties_.pack(p); + return length(); +} + +of_error TableFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_table_features *tf = + (struct of13::ofp_table_features*) buffer; + this->length_ = ntoh16(tf->length); + this->table_id_ = tf->table_id; + this->name_ = std::string(tf->name); + this->metadata_match_ = ntoh64(tf->metadata_match); + this->metadata_write_ = ntoh64(tf->metadata_write); + this->config_ = ntoh32(tf->config); + this->max_entries_ = ntoh32(tf->max_entries); + uint8_t *p = buffer + sizeof(struct of13::ofp_table_features); + this->properties_.length( + this->length_ - sizeof(struct of13::ofp_table_features)); + this->properties_.unpack(p); + return 0; +} + +void TableFeatures::properties(TablePropertiesList properties) { + this->properties_ = properties; + this->length_ += properties.length(); + +} + +void TableFeatures::add_table_prop(TableFeatureProp* prop) { + this->properties_.add_property(prop); + this->length_ += prop->length() + prop->padding(); +} + +TableFeatureProp* TableFeatures::make_table_feature_prop(uint16_t type) { + if (type == OFPTFPT_INSTRUCTIONS || type == OFPTFPT_INSTRUCTIONS_MISS) { + return new TableFeaturePropInstruction(type); + } + if (type == OFPTFPT_NEXT_TABLES || type == OFPTFPT_NEXT_TABLES_MISS) { + return new TableFeaturePropNextTables(type); + } + if (type == OFPTFPT_WRITE_ACTIONS || type == OFPTFPT_WRITE_ACTIONS_MISS + || type == OFPTFPT_APPLY_ACTIONS + || type == OFPTFPT_APPLY_ACTIONS_MISS) { + return new TableFeaturePropActions(type); + } + if (type == OFPTFPT_MATCH || type == OFPTFPT_WILDCARDS + || type == OFPTFPT_WRITE_SETFIELD || type == OFPTFPT_WRITE_SETFIELD_MISS + || type == OFPTFPT_APPLY_SETFIELD + || type == OFPTFPT_APPLY_SETFIELD_MISS) { + return new TableFeaturePropOXM(type); + } + if (type == OFPTFPT_EXPERIMENTER || type == OFPTFPT_EXPERIMENTER_MISS) { + return new TableFeaturePropExperimenter(type); + } + return NULL; +} + +} //End of namespace fluid_msg + +QueueProperty* QueueProperty::make_queue_of13_property(uint16_t property) { + switch (property) { + case (of13::OFPQT_MAX_RATE): { + return new of13::QueuePropMaxRate(); + } + case (of13::OFPQT_MIN_RATE): { + return new of13::QueuePropMinRate(); + } + case (of13::OFPQT_EXPERIMENTER): { + return new of13::QueueExperimenter(); + } + } + return NULL; +} + +} //End namespace of13 diff --git a/src/ovs/libfluid-msg/of13/of13instruction.cc b/src/ovs/libfluid-msg/of13/of13instruction.cc new file mode 100644 index 00000000..087deeaa --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13instruction.cc @@ -0,0 +1,416 @@ +#include "libfluid-msg/of13/of13instruction.hh" + +namespace fluid_msg { + +namespace of13 { + +Instruction::Instruction() + : type_(0), + length_(0) { +} + +Instruction::Instruction(uint16_t type, uint16_t length) + : type_(type), + length_(length) { +} + +bool Instruction::equals(const Instruction &other) { + return (*this == other); +} + +bool Instruction::operator==(const Instruction &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool Instruction::operator!=(const Instruction &other) const { + return !(*this == other); +} + +InstructionSet::InstructionSet(std::set instruction_set) { + this->instruction_set_ = instruction_set_; + for (std::set::const_iterator it = instruction_set.begin(); + it != instruction_set.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +InstructionSet::InstructionSet(const InstructionSet &other) { + this->length_ = other.length_; + for (std::set::const_iterator it = + other.instruction_set_.begin(); it != other.instruction_set_.end(); + ++it) { + this->instruction_set_.insert((*it)->clone()); + } +} + +bool InstructionSet::operator==(const InstructionSet &other) const { + std::set::const_iterator ot = other.instruction_set_.begin(); + for (std::set::const_iterator it = + this->instruction_set_.begin(); it != this->instruction_set_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool InstructionSet::operator!=(const InstructionSet &other) const { + return !(*this == other); +} + +InstructionSet::~InstructionSet() { + for (std::set::const_iterator it = + this->instruction_set_.begin(); it != this->instruction_set_.end(); + ++it) { + delete *it; + } +} + +size_t InstructionSet::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::set::iterator it = this->instruction_set_.begin(), + end = this->instruction_set_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +of_error InstructionSet::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Instruction *inst; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + inst = Instruction::make_instruction(type); + inst->unpack(p); + this->instruction_set_.insert(inst); + len -= inst->length(); + p += inst->length(); + } + return 0; +} + +InstructionSet& InstructionSet::operator=(InstructionSet other) { + swap(*this, other); + return *this; +} + +void swap(InstructionSet& first, InstructionSet& second) { + + std::swap(first.length_, second.length_); + std::swap(first.instruction_set_, second.instruction_set_); +} + +void InstructionSet::add_instruction(Instruction &inst) { + Instruction* instp = inst.clone(); + this->instruction_set_.insert(instp); + this->length_ += inst.length(); +} + +void InstructionSet::add_instruction(Instruction *inst) { + this->instruction_set_.insert(inst); + this->length_ += inst->length(); +} + +Instruction* Instruction::make_instruction(uint16_t type) { + switch (type) { + case (of13::OFPIT_GOTO_TABLE): { + return new GoToTable(); + } + case (of13::OFPIT_WRITE_METADATA): { + return new WriteMetadata(); + } + case (of13::OFPIT_CLEAR_ACTIONS): { + return new ClearActions(); + } + case (of13::OFPIT_WRITE_ACTIONS): { + return new WriteActions(); + } + case (of13::OFPIT_APPLY_ACTIONS): { + return new ApplyActions(); + } + case (of13::OFPIT_METER): { + return new Meter(); + } + case (of13::OFPIT_EXPERIMENTER): { + return new InstructionExperimenter(); + } + } + return NULL; +} + +size_t Instruction::pack(uint8_t* buffer) { + struct of13::ofp_instruction *in = (struct of13::ofp_instruction *) buffer; + in->type = hton16(this->type_); + in->len = hton16(this->length_); + return 0; +} + +of_error Instruction::unpack(uint8_t* buffer) { + struct of13::ofp_instruction *in = (struct of13::ofp_instruction *) buffer; + this->type_ = ntoh16(in->type); + this->length_ = ntoh16(in->len); + return 0; +} + +GoToTable::GoToTable(uint8_t table_id) + : Instruction(of13::OFPIT_GOTO_TABLE, + sizeof(struct of13::ofp_instruction_goto_table)), + set_order_(60) { + this->table_id_ = table_id; +} + +bool GoToTable::equals(const Instruction &other) { + + if (const GoToTable * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->table_id_ == inst->table_id_)); + } + else { + return false; + } +} + +size_t GoToTable::pack(uint8_t* buffer) { + struct of13::ofp_instruction_goto_table *go = + (struct of13::ofp_instruction_goto_table *) buffer; + Instruction::pack(buffer); + go->table_id = this->table_id_; + memset(go->pad, 0x0, 3); + return 0; +} + +of_error GoToTable::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_goto_table *go = + (struct of13::ofp_instruction_goto_table *) buffer; + Instruction::unpack(buffer); + this->table_id_ = go->table_id; + return 0; +} + +WriteMetadata::WriteMetadata(uint64_t metadata, uint64_t metadata_mask) + : Instruction(of13::OFPIT_WRITE_METADATA, + sizeof(struct of13::ofp_instruction_write_metadata)), + set_order_(50) { + this->metadata_ = metadata; + this->metadata_mask_ = metadata_mask; +} + +bool WriteMetadata::equals(const Instruction &other) { + + if (const WriteMetadata * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->metadata_mask_ == inst->metadata_mask_)); + } + else { + return false; + } +} + +size_t WriteMetadata::pack(uint8_t* buffer) { + struct of13::ofp_instruction_write_metadata *wm = + (struct of13::ofp_instruction_write_metadata *) buffer; + Instruction::pack(buffer); + memset(wm->pad, 0x0, 4); + wm->metadata = hton64(this->metadata_); + wm->metadata_mask = hton64(this->metadata_mask_); + return 0; +} + +of_error WriteMetadata::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_write_metadata *wm = + (struct of13::ofp_instruction_write_metadata *) buffer; + Instruction::unpack(buffer); + this->metadata_ = ntoh64(wm->metadata); + this->metadata_mask_ = ntoh64(wm->metadata_mask); + return 0; +} + +WriteActions::WriteActions(ActionSet actions_) + : Instruction(of13::OFPIT_WRITE_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(40) { + actions(actions_); +} + +bool WriteActions::equals(const Instruction &other) { + if (const WriteActions * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->actions_ == inst->actions_)); + } + else { + return false; + } +} + +void WriteActions::actions(ActionSet actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void WriteActions::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void WriteActions::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t WriteActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction_actions *ia = + (struct of13::ofp_instruction_actions*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + uint8_t *p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.pack(p); + return 0; +} + +of_error WriteActions::unpack(uint8_t* buffer) { + Instruction::unpack(buffer); + uint8_t* p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.length( + this->length_ - sizeof(struct of13::ofp_instruction_actions)); + this->actions_.unpack(p); + return 0; +} + +ApplyActions::ApplyActions(ActionList actions_) + : Instruction(of13::OFPIT_APPLY_ACTIONS, + sizeof(struct of13::ofp_instruction_actions)), + set_order_(20) { + actions(actions_); +} + +bool ApplyActions::equals(const Instruction &other) { + if (const ApplyActions * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->actions_ == inst->actions_)); + } + else { + return false; + } +} + +void ApplyActions::actions(ActionList actions) { + this->actions_ = actions; + this->length_ += actions.length(); +} + +void ApplyActions::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); +} + +void ApplyActions::add_action(Action* action) { + this->actions_.add_action(action); + this->length_ += action->length(); +} + +size_t ApplyActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction_actions *ia = + (struct of13::ofp_instruction_actions*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + uint8_t *p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.pack(p); + return 0; +} + +of_error ApplyActions::unpack(uint8_t* buffer) { + Instruction::unpack(buffer); + uint8_t* p = buffer + sizeof(struct of13::ofp_instruction_actions); + this->actions_.length( + this->length_ - sizeof(struct of13::ofp_instruction_actions)); + this->actions_.unpack13(p); + return 0; +} + +size_t ClearActions::pack(uint8_t* buffer) { + struct of13::ofp_instruction *ia = (struct of13::ofp_instruction*) buffer; + Instruction::pack(buffer); + memset(ia->pad, 0x0, 4); + return 0; +} + +of_error ClearActions::unpack(uint8_t* buffer) { + struct of13::ofp_instruction *ia = (struct of13::ofp_instruction*) buffer; + Instruction::unpack(buffer); + return 0; +} + +Meter::Meter(uint32_t meter_id) + : Instruction(of13::OFPIT_METER, + sizeof(struct of13::ofp_instruction_meter)), + set_order_(10) { + this->meter_id_ = meter_id; +} + +bool Meter::equals(const Instruction &other) { + + if (const Meter * inst = dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->meter_id_ == inst->meter_id_)); + } + else { + return false; + } +} + +size_t Meter::pack(uint8_t* buffer) { + struct of13::ofp_instruction_meter *im = + (struct of13::ofp_instruction_meter *) buffer; + Instruction::pack(buffer); + im->meter_id = hton32(this->meter_id_); + return 0; +} + +of_error Meter::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_meter *im = + (struct of13::ofp_instruction_meter *) buffer; + Instruction::unpack(buffer); + this->meter_id_ = ntoh32(im->meter_id); + return 0; +} + +InstructionExperimenter::InstructionExperimenter(uint32_t experimenter) + : Instruction(of13::OFPIT_EXPERIMENTER, + sizeof(struct of13::ofp_instruction_experimenter)) { + this->experimenter_ = experimenter; +} + +bool InstructionExperimenter::equals(const Instruction &other) { + + if (const InstructionExperimenter * inst = + dynamic_cast(&other)) { + return ((Instruction::equals(other)) + && (this->experimenter_ == inst->experimenter_)); + } + else { + return false; + } +} + +size_t InstructionExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_instruction_experimenter *ie = + (struct of13::ofp_instruction_experimenter *) buffer; + Instruction::pack(buffer); + ie->experimenter = hton32(this->experimenter_); + return 0; +} + +of_error InstructionExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_instruction_experimenter *ie = + (struct of13::ofp_instruction_experimenter *) buffer; + Instruction::unpack(buffer); + this->experimenter_ = ntoh32(ie->experimenter); + return 0; +} + +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of13/of13match.cc b/src/ovs/libfluid-msg/of13/of13match.cc new file mode 100644 index 00000000..0194704c --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13match.cc @@ -0,0 +1,2733 @@ +#include "libfluid-msg/of13/of13match.hh" +#include +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +namespace of13 { + +MatchHeader::MatchHeader() + : type_(0), + length_(0) { +} + +MatchHeader::MatchHeader(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool MatchHeader::operator==(const MatchHeader &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool MatchHeader::operator!=(const MatchHeader &other) const { + return !(*this == other); +} + +size_t MatchHeader::pack(uint8_t *buffer) { + struct of13::ofp_match *m = (struct of13::ofp_match*) buffer; + m->type = hton16(this->type_); + m->length = hton16(this->length_); + return 0; +} + +of_error MatchHeader::unpack(uint8_t *buffer) { + struct of13::ofp_match *m = (struct of13::ofp_match*) buffer; + this->type_ = ntoh16(m->type); + this->length_ = ntoh16(m->length); + if (this->length_ < sizeof(struct of13::ofp_match)) { + return openflow_error(of13::OFPET_BAD_MATCH, of13::OFPBMC_BAD_LEN); + } + return 0; +} + +OXMTLV::OXMTLV() + : class__(0), + field_(0), + has_mask_(0), + length_(0) { +} + +OXMTLV::OXMTLV(uint16_t class_, uint8_t field, bool has_mask, uint8_t length) + : class__(class_), + field_(field), + has_mask_(has_mask), + length_(has_mask?length<<1:length) { +} + +bool OXMTLV::equals(const OXMTLV &other) { + return ((this->class__ == other.class__) && (this->field_ == other.field_) + && (this->has_mask_ == other.has_mask_) + && (this->length_ == other.length_)); +} + +bool OXMTLV::operator==(const OXMTLV &other) const { + return ((this->class__ == other.class__) && (this->field_ == other.field_) + && (this->has_mask_ && other.has_mask_) + && (this->length_ == other.length_)); +} + +bool OXMTLV::operator!=(const OXMTLV &other) const { + return !(*this == other); +} + +OXMTLV& OXMTLV::operator=(const OXMTLV& field) { + this->class__ = field.class__; + this->field_ = field.field_; + this->has_mask_ = field.has_mask_; + this->length_ = field.length_; + return *this; +} + +void OXMTLV::create_oxm_req(uint16_t eth_type1, uint16_t eth_type2, + uint8_t ip_proto, uint8_t icmp) { + this->reqs.eth_type_req[0] = eth_type1; + this->reqs.eth_type_req[1] = eth_type2; + this->reqs.ip_proto_req = ip_proto; + this->reqs.icmp_req = icmp; +} + +size_t OXMTLV::pack(uint8_t *buffer) { + uint32_t header = hton32( + OXMTLV::make_header(this->class__, this->field_, this->has_mask_, + this->length_)); + memcpy(buffer, &header, sizeof(uint32_t)); + return 0; +} + +of_error OXMTLV::unpack(uint8_t *buffer) { + uint32_t header = ntoh32(*((uint32_t*) buffer)); + this->class__ = oxm_class(header); + this->field_ = oxm_field(header); + this->has_mask_ = oxm_has_mask(header); + this->length_ = oxm_length(header); + return 0; +} + +uint32_t OXMTLV::make_header(uint16_t class_, uint8_t field, bool has_mask, + uint8_t length) { + return (((class_) << 16) | ((field) << 9) | ((has_mask ? 1 : 0) << 8) + | (length)); + +} + +uint16_t OXMTLV::oxm_class(uint32_t header) { + return ((header) >> 16); +} + +uint8_t OXMTLV::oxm_field(uint32_t header) { + return (((header) >> 9) & 0x7f); +} + +bool OXMTLV::oxm_has_mask(uint32_t header) { + return (((header) >> 8) & 1); + +} + +uint8_t OXMTLV::oxm_length(uint32_t header) { + return ((header) & 0xff); +} + +InPort::InPort() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PORT, false, + of13::OFP_OXM_IN_PORT_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +InPort::InPort(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PORT, false, + of13::OFP_OXM_IN_PORT_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool InPort::equals(const OXMTLV &other) { + if (const InPort * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& InPort::operator=(const OXMTLV& field) { + const InPort& port = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = port.value_; + return *this; +} +; + +size_t InPort::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error InPort::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +InPhyPort::InPhyPort() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PHY_PORT, false, + of13::OFP_OXM_IN_PHY_PORT_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +InPhyPort::InPhyPort(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IN_PHY_PORT, false, + of13::OFP_OXM_IN_PHY_PORT_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool InPhyPort::equals(const OXMTLV &other) { + + if (const InPhyPort * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& InPhyPort::operator=(const OXMTLV& field) { + const InPhyPort& phy_port = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = phy_port.value_; + return *this; +} +; + +size_t InPhyPort::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error InPhyPort::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +Metadata::Metadata() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, false, + of13::OFP_OXM_METADATA_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +Metadata::Metadata(uint64_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, false, + of13::OFP_OXM_METADATA_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +Metadata::Metadata(uint64_t value, uint64_t mask) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_METADATA, true, + of13::OFP_OXM_METADATA_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool Metadata::equals(const OXMTLV &other) { + + if (const Metadata * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& Metadata::operator=(const OXMTLV& field) { + const Metadata& meta = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = meta.value_; + this->mask_ = meta.mask_; + return *this; +} +; + +size_t Metadata::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint64_t mask = hton64(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint64_t value = hton64(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error Metadata::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh64(*((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh64( + *((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN + len))); + } + return 0; +} + +EthDst::EthDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthDst::EthDst(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +EthDst::EthDst(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_DST, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool EthDst::equals(const OXMTLV &other) { + + if (const EthDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& EthDst::operator=(const OXMTLV& field) { + const EthDst& dst = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dst.value_; + this->mask_ = dst.mask_; + return *this; +} +; + +size_t EthDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error EthDst::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +EthSrc::EthSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthSrc::EthSrc(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +EthSrc::EthSrc(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_SRC, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool EthSrc::equals(const OXMTLV &other) { + + if (const EthSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& EthSrc::operator=(const OXMTLV& field) { + const EthSrc& src = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = src.value_; + this->mask_ = src.mask_; + return *this; +} +; + +size_t EthSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error EthSrc::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +EthType::EthType() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_TYPE, false, + of13::OFP_OXM_ETH_TYPE_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +EthType::EthType(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ETH_TYPE, false, + of13::OFP_OXM_ETH_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool EthType::equals(const OXMTLV &other) { + + if (const EthType * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& EthType::operator=(const OXMTLV& field) { + const EthType& type = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = type.value_; + return *this; +} +; + +size_t EthType::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error EthType::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +VLANVid::VLANVid() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, false, + of13::OFP_OXM_VLAN_VID_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +VLANVid::VLANVid(uint16_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, false, + of13::OFP_OXM_VLAN_VID_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +VLANVid::VLANVid(uint16_t value, uint16_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_VID, true, + of13::OFP_OXM_VLAN_VID_LEN) { + this->mask_ = mask; + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool VLANVid::equals(const OXMTLV &other) { + + if (const VLANVid * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& VLANVid::operator=(const OXMTLV& field) { + const VLANVid& id = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = id.value_; + this->mask_ = id.mask_; + return *this; +} +; + +size_t VLANVid::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint16_t mask = hton16(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error VLANVid::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh16( + *((uint16_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +VLANPcp::VLANPcp() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_PCP, false, + of13::OFP_OXM_VLAN_PCP_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +VLANPcp::VLANPcp(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_VLAN_PCP, false, + of13::OFP_OXM_VLAN_PCP_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +bool VLANPcp::equals(const OXMTLV &other) { + + if (const VLANPcp * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& VLANPcp::operator=(const OXMTLV& field) { + const VLANPcp& pcp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = pcp.value_; + return *this; +} +; + +size_t VLANPcp::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error VLANPcp::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPDSCP::IPDSCP() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_DSCP, false, + of13::OFP_OXM_IP_DSCP_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPDSCP::IPDSCP(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_DSCP, false, + of13::OFP_OXM_IP_DSCP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPDSCP::equals(const OXMTLV &other) { + + if (const IPDSCP * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPDSCP::operator=(const OXMTLV& field) { + const IPDSCP& dscp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dscp.value_; + return *this; +} +; + +size_t IPDSCP::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPDSCP::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPECN::IPECN() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_ECN, false, + of13::OFP_OXM_IP_DSCP_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPECN::IPECN(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_ECN, false, + of13::OFP_OXM_IP_DSCP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPECN::equals(const OXMTLV &other) { + + if (const IPECN * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPECN::operator=(const OXMTLV& field) { + const IPECN& ecn = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ecn.value_; + return *this; +} +; + +size_t IPECN::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPECN::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPProto::IPProto() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_PROTO, false, + of13::OFP_OXM_IP_PROTO_LEN) { + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +IPProto::IPProto(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IP_PROTO, false, + of13::OFP_OXM_IP_PROTO_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 0, 0); +} + +bool IPProto::equals(const OXMTLV &other) { + + if (const IPProto * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPProto::operator=(const OXMTLV& field) { + const IPProto& proto = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = proto.value_; + return *this; +} +; + +size_t IPProto::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error IPProto::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *(buffer + of13::OFP_OXM_HEADER_LEN); + return 0; +} + +IPv4Src::IPv4Src() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, false, + of13::OFP_OXM_IPV4_LEN), + value_((uint32_t) 0), + mask_((uint32_t) 0) { + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Src::IPv4Src(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, false, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_((uint32_t) 0) { + // this->value_ = value; + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Src::IPv4Src(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_SRC, true, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_(mask) { + // this->value_ = value; + // this->mask_ = mask; + create_oxm_req(0x0800, 0, 0, 0); +} + +bool IPv4Src::equals(const OXMTLV &other) { + + if (const IPv4Src * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv4Src::operator=(const OXMTLV& field) { + const IPv4Src& src = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = src.value_; + this->mask_ = src.mask_; + return *this; +} +; + +size_t IPv4Src::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error IPv4Src::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +IPv4Dst::IPv4Dst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, false, + of13::OFP_OXM_IPV4_LEN), + value_((uint32_t) 0), + mask_((uint32_t) 0) { + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Dst::IPv4Dst(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, false, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_((uint32_t) 0) { + // this->value_ = value; + create_oxm_req(0x0800, 0, 0, 0); +} + +IPv4Dst::IPv4Dst(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV4_DST, true, + of13::OFP_OXM_IPV4_LEN), + value_(value), + mask_(mask) { + // this->value_ = value; + // this->mask_ = mask; + create_oxm_req(0x0800, 0, 0, 0); +} + +bool IPv4Dst::equals(const OXMTLV &other) { + + if (const IPv4Dst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv4Dst::operator=(const OXMTLV& field) { + const IPv4Dst& dst = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = dst.value_; + this->mask_ = dst.mask_; + return *this; +} +; + +size_t IPv4Dst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error IPv4Dst::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +TCPSrc::TCPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +TCPSrc::TCPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +bool TCPSrc::equals(const OXMTLV &other) { + + if (const TCPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& TCPSrc::operator=(const OXMTLV& field) { + const TCPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t TCPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error TCPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +TCPDst::TCPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +TCPDst::TCPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TCP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 6, 0); +} + +bool TCPDst::equals(const OXMTLV &other) { + + if (const TCPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& TCPDst::operator=(const OXMTLV& field) { + const TCPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t TCPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error TCPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +UDPSrc::UDPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +UDPSrc::UDPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +bool UDPSrc::equals(const OXMTLV &other) { + + if (const UDPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& UDPSrc::operator=(const OXMTLV& field) { + const UDPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t UDPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error UDPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +UDPDst::UDPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +UDPDst::UDPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_UDP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 17, 0); +} + +bool UDPDst::equals(const OXMTLV &other) { + + if (const UDPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& UDPDst::operator=(const OXMTLV& field) { + const UDPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t UDPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error UDPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +SCTPSrc::SCTPSrc() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_SRC, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +SCTPSrc::SCTPSrc(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_SRC, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +bool SCTPSrc::equals(const OXMTLV &other) { + + if (const SCTPSrc * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& SCTPSrc::operator=(const OXMTLV& field) { + const SCTPSrc& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t SCTPSrc::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error SCTPSrc::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +SCTPDst::SCTPDst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_DST, false, + of13::OFP_OXM_TP_LEN) { + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +SCTPDst::SCTPDst(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_SCTP_DST, false, + of13::OFP_OXM_TP_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0x86dd, 132, 0); +} + +bool SCTPDst::equals(const OXMTLV &other) { + + if (const SCTPDst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& SCTPDst::operator=(const OXMTLV& field) { + const SCTPDst& tp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tp.value_; + return *this; +} +; + +size_t SCTPDst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error SCTPDst::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +ICMPv4Type::ICMPv4Type() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + create_oxm_req(0x0800, 0, 1, 0); +} + +ICMPv4Type::ICMPv4Type(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0, 1, 0); +} + +bool ICMPv4Type::equals(const OXMTLV &other) { + + if (const ICMPv4Type * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv4Type::operator=(const OXMTLV& field) { + const ICMPv4Type& type = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = type.value_; + return *this; +} +; + +size_t ICMPv4Type::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv4Type::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; + +} + +ICMPv4Code::ICMPv4Code() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + create_oxm_req(0x0800, 0, 1, 0); +} + +ICMPv4Code::ICMPv4Code(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV4_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + this->value_ = value; + create_oxm_req(0x0800, 0, 1, 0); +} + +bool ICMPv4Code::equals(const OXMTLV &other) { + + if (const ICMPv4Code * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv4Code::operator=(const OXMTLV& field) { + const ICMPv4Code& code = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = code.value_; + return *this; +} +; + +size_t ICMPv4Code::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv4Code::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +ARPOp::ARPOp() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_OP, false, + of13::OFP_OXM_ARP_OP_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPOp::ARPOp(uint16_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_OP, false, + of13::OFP_OXM_ARP_OP_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPOp::equals(const OXMTLV &other) { + + if (const ARPOp * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ARPOp::operator=(const OXMTLV& field) { + const ARPOp& op = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = op.value_; + return *this; +} +; + +size_t ARPOp::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error ARPOp::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +ARPSPA::ARPSPA() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, false, + of13::OFP_OXM_IPV4_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSPA::ARPSPA(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, false, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSPA::ARPSPA(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SPA, true, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + this->mask_ = mask; +} + +bool ARPSPA::equals(const OXMTLV &other) { + + if (const ARPSPA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPSPA::operator=(const OXMTLV& field) { + const ARPSPA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPSPA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error ARPSPA::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +ARPTPA::ARPTPA() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, false, + of13::OFP_OXM_IPV4_LEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTPA::ARPTPA(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, false, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTPA::ARPTPA(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_TPA, true, + of13::OFP_OXM_IPV4_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPTPA::equals(const OXMTLV &other) { + + if (const ARPTPA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPTPA::operator=(const OXMTLV& field) { + const ARPTPA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPTPA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t ip_mask = this->mask_.getIPv4(); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &ip_mask, len); + } + uint32_t ip = this->value_.getIPv4(); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &ip, len); + return 0; +} + +of_error ARPTPA::unpack(uint8_t *buffer) { + uint32_t ip = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + uint32_t ip_mask = *((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN + + len)); + this->mask_ = IPAddress(ip_mask); + } + return 0; +} + +ARPSHA::ARPSHA() + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, false, + OFP_ETH_ALEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSHA::ARPSHA(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPSHA::ARPSHA(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_SHA, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPSHA::equals(const OXMTLV &other) { + + if (const ARPSHA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPSHA::operator=(const OXMTLV& field) { + const ARPSHA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPSHA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error ARPSHA::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +ARPTHA::ARPTHA() + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, false, + OFP_ETH_ALEN) { + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTHA::ARPTHA(EthAddress value) + : mask_("ff:ff:ff:ff:ff:ff"), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0x0806, 0, 0, 0); +} + +ARPTHA::ARPTHA(EthAddress value, EthAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ARP_THA, true, + OFP_ETH_ALEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x0806, 0, 0, 0); +} + +bool ARPTHA::equals(const OXMTLV &other) { + + if (const ARPTHA * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& ARPTHA::operator=(const OXMTLV& field) { + const ARPTHA& arp = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = arp.value_; + this->mask_ = arp.mask_; + return *this; +} +; + +size_t ARPTHA::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), + this->mask_.get_data(), len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), len); + return 0; +} + +of_error ARPTHA::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + if (this->has_mask_) { + size_t len = this->length_ / 2; + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN + len, OFP_ETH_ALEN); + this->mask_ = EthAddress(v); + } + return 0; +} + +IPv6Src::IPv6Src() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, false, + of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Src::IPv6Src(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, false, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Src::IPv6Src(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_SRC, true, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Src::equals(const OXMTLV &other) { + + if (const IPv6Src * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Src::operator=(const OXMTLV& field) { + const IPv6Src& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPv6Src::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), this->mask_.getIPv6(), + len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), len); + return 0; +} + +of_error IPv6Src::unpack(uint8_t *buffer) { + // uint8_t *ip = buffer + of13::OFP_OXM_HEADER_LEN; + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + if (this->has_mask_) { + size_t len = this->length_ / 2; + ip += 1; + this->mask_ = IPAddress(*ip); + } + return 0; +} + +IPv6Dst::IPv6Dst() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, false, + of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Dst::IPv6Dst(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, false, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Dst::IPv6Dst(IPAddress value, IPAddress mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_DST, true, + of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Dst::equals(const OXMTLV &other) { + + if (const IPv6Dst * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Dst::operator=(const OXMTLV& field) { + const IPv6Dst& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPv6Dst::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), this->mask_.getIPv6(), + len); + } + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), len); + return 0; +} + +of_error IPv6Dst::unpack(uint8_t *buffer) { + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + // uint8_t *ip = buffer + of13::OFP_OXM_HEADER_LEN; + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + if (this->has_mask_) { + ip += 1; + this->mask_ = IPAddress(*ip); + } + return 0; +} + +IPV6Flabel::IPV6Flabel() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, false, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPV6Flabel::IPV6Flabel(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, false, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPV6Flabel::IPV6Flabel(uint32_t value, uint32_t mask) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_FLABEL, true, + of13::OFP_OXM_IPV6_FLABEL_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPV6Flabel::equals(const OXMTLV &other) { + + if (const IPV6Flabel * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPV6Flabel::operator=(const OXMTLV& field) { + const IPV6Flabel& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + this->mask_ = ipv6.mask_; + return *this; +} +; + +size_t IPV6Flabel::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t mask = hton32(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error IPV6Flabel::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh32( + *((uint32_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +ICMPv6Type::ICMPv6Type() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + create_oxm_req(0, 0x86dd, 58, 0); +} + +ICMPv6Type::ICMPv6Type(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_TYPE, false, + of13::OFP_OXM_ICMP_TYPE_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 0); +} + +bool ICMPv6Type::equals(const OXMTLV &other) { + + if (const ICMPv6Type * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv6Type::operator=(const OXMTLV& field) { + const ICMPv6Type& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t ICMPv6Type::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv6Type::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +ICMPv6Code::ICMPv6Code() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + create_oxm_req(0, 0x86dd, 58, 0); +} + +ICMPv6Code::ICMPv6Code(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_ICMPV6_CODE, false, + of13::OFP_OXM_ICMP_CODE_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 0); +} + +bool ICMPv6Code::equals(const OXMTLV &other) { + + if (const ICMPv6Code * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& ICMPv6Code::operator=(const OXMTLV& field) { + const ICMPv6Code& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t ICMPv6Code::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error ICMPv6Code::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +IPv6NDTarget::IPv6NDTarget() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TARGET, + false, of13::OFP_OXM_IPV6_LEN) { + create_oxm_req(0, 0x86dd, 58, 135); +} + +IPv6NDTarget::IPv6NDTarget(IPAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TARGET, + false, of13::OFP_OXM_IPV6_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 135); +} + +bool IPv6NDTarget::equals(const OXMTLV &other) { + + if (const IPv6NDTarget * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDTarget::operator=(const OXMTLV& field) { + const IPv6NDTarget& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDTarget::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.getIPv6(), + this->length_); + return 0; +} + +of_error IPv6NDTarget::unpack(uint8_t *buffer) { + struct in6_addr *ip = + (struct in6_addr *) (buffer + of13::OFP_OXM_HEADER_LEN); + OXMTLV::unpack(buffer); + this->value_ = IPAddress(*ip); + return 0; +} + +IPv6NDTLL::IPv6NDTLL() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TLL, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0x86dd, 58, 136); +} + +IPv6NDTLL::IPv6NDTLL(EthAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_TLL, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 136); +} + +bool IPv6NDTLL::equals(const OXMTLV &other) { + + if (const IPv6NDTLL * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDTLL::operator=(const OXMTLV& field) { + const IPv6NDTLL& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDTLL::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), + this->length_); + return 0; +} + +of_error IPv6NDTLL::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + return 0; +} + +IPv6NDSLL::IPv6NDSLL() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_SLL, false, + OFP_ETH_ALEN) { + create_oxm_req(0, 0x86dd, 58, 136); +} + +IPv6NDSLL::IPv6NDSLL(EthAddress value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_ND_SLL, false, + OFP_ETH_ALEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 58, 136); +} + +bool IPv6NDSLL::equals(const OXMTLV &other) { + + if (const IPv6NDSLL * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& IPv6NDSLL::operator=(const OXMTLV& field) { + const IPv6NDSLL& ipv6 = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = ipv6.value_; + return *this; +} +; + +size_t IPv6NDSLL::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, this->value_.get_data(), + this->length_); + return 0; +} + +of_error IPv6NDSLL::unpack(uint8_t *buffer) { + uint8_t v[OFP_ETH_ALEN]; + OXMTLV::unpack(buffer); + memcpy(v, buffer + of13::OFP_OXM_HEADER_LEN, OFP_ETH_ALEN); + this->value_ = EthAddress(v); + return 0; +} + +MPLSLabel::MPLSLabel() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_LABEL, false, + of13::OFP_OXM_MPLS_LABEL_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSLabel::MPLSLabel(uint32_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_LABEL, false, + of13::OFP_OXM_MPLS_LABEL_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSLabel::equals(const OXMTLV &other) { + + if (const MPLSLabel * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSLabel::operator=(const OXMTLV& field) { + const MPLSLabel& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSLabel::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, this->length_); + return 0; +} + +of_error MPLSLabel::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + return 0; +} + +MPLSTC::MPLSTC() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_TC, false, + of13::OFP_OXM_MPLS_TC_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSTC::MPLSTC(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_TC, false, + of13::OFP_OXM_MPLS_TC_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSTC::equals(const OXMTLV &other) { + + if (const MPLSTC * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSTC::operator=(const OXMTLV& field) { + const MPLSTC& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSTC::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error MPLSTC::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +MPLSBOS::MPLSBOS() + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_BOS, false, + of13::OFP_OXM_MPLS_BOS_LEN) { + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +MPLSBOS::MPLSBOS(uint8_t value) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_MPLS_BOS, false, + of13::OFP_OXM_MPLS_BOS_LEN) { + this->value_ = value; + create_oxm_req(0x8847, 0x8848, 0, 0); +} + +bool MPLSBOS::equals(const OXMTLV &other) { + + if (const MPLSBOS * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_)); + } + else { + return false; + } +} + +OXMTLV& MPLSBOS::operator=(const OXMTLV& field) { + const MPLSBOS& mpls = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = mpls.value_; + return *this; +} +; + +size_t MPLSBOS::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &this->value_, this->length_); + return 0; +} + +of_error MPLSBOS::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = *((uint8_t*) (buffer + of13::OFP_OXM_HEADER_LEN)); + return 0; +} + +PBBIsid::PBBIsid() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, false, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + create_oxm_req(0x88E7, 0, 0, 0); +} + +PBBIsid::PBBIsid(uint32_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, false, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + this->value_ = value; + create_oxm_req(0x88E7, 0, 0, 0); +} + +PBBIsid::PBBIsid(uint32_t value, uint32_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_PBB_ISID, true, + of13::OFP_OXM_IPV6_PBB_ISID_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0x88E7, 0, 0, 0); +} + +bool PBBIsid::equals(const OXMTLV &other) { + + if (const PBBIsid * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& PBBIsid::operator=(const OXMTLV& field) { + const PBBIsid& pbb = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = pbb.value_; + this->mask_ = pbb.mask_; + return *this; +} +; + +size_t PBBIsid::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint32_t mask = hton32(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint32_t value = hton32(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error PBBIsid::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint32_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh32( + *((uint32_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +TUNNELId::TUNNELId() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TUNNEL_ID, false, + of13::OFP_OXM_TUNNEL_ID_LEN) { + create_oxm_req(0, 0, 0, 0); +} + +TUNNELId::TUNNELId(uint64_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_TUNNEL_ID, false, + of13::OFP_OXM_TUNNEL_ID_LEN) { + this->value_ = value; + create_oxm_req(0, 0, 0, 0); +} + +TUNNELId::TUNNELId(uint64_t value, uint64_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFP_OXM_TUNNEL_ID_LEN, true, + of13::OFP_OXM_TUNNEL_ID_LEN) { + this->value_ = value; + this->mask_ = mask; + create_oxm_req(0, 0, 0, 0); +} + +bool TUNNELId::equals(const OXMTLV &other) { + + if (const TUNNELId * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& TUNNELId::operator=(const OXMTLV& field) { + const TUNNELId& tunnel = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = tunnel.value_; + this->mask_ = tunnel.mask_; + return *this; +} + +size_t TUNNELId::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint64_t mask = hton64(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint64_t value = hton64(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error TUNNELId::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh32(*((uint64_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh64( + *((uint64_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +IPv6Exthdr::IPv6Exthdr() + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, false, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Exthdr::IPv6Exthdr(uint16_t value) + : mask_(0), + OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, false, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +IPv6Exthdr::IPv6Exthdr(uint16_t value, uint16_t mask) + : OXMTLV(of13::OFPXMC_OPENFLOW_BASIC, of13::OFPXMT_OFB_IPV6_EXTHDR, true, + of13::OFP_OXM_IPV6_EXTHDR_LEN) { + this->mask_ = mask; + this->value_ = value; + create_oxm_req(0, 0x86dd, 0, 0); +} + +bool IPv6Exthdr::equals(const OXMTLV &other) { + + if (const IPv6Exthdr * field = dynamic_cast(&other)) { + return ((OXMTLV::equals(other)) && (this->value_ == field->value_) + && (this->has_mask_ ? this->mask_ == field->mask_ : true)); + } + else { + return false; + } +} + +OXMTLV& IPv6Exthdr::operator=(const OXMTLV& field) { + const IPv6Exthdr& hdr = dynamic_cast(field); + OXMTLV::operator=(field); + this->value_ = hdr.value_; + this->mask_ = hdr.mask_; + return *this; +} +; + +size_t IPv6Exthdr::pack(uint8_t *buffer) { + OXMTLV::pack(buffer); + size_t len = this->length_; + if (this->has_mask_) { + len = this->length_ / 2; + uint16_t mask = hton16(this->mask_); + memcpy(buffer + (of13::OFP_OXM_HEADER_LEN + len), &mask, len); + } + uint16_t value = hton16(this->value_); + memcpy(buffer + of13::OFP_OXM_HEADER_LEN, &value, len); + return 0; +} + +of_error IPv6Exthdr::unpack(uint8_t *buffer) { + OXMTLV::unpack(buffer); + this->value_ = ntoh16(*((uint16_t*) (buffer + of13::OFP_OXM_HEADER_LEN))); + if (this->has_mask_) { + size_t len = this->length_ / 2; + this->mask_ = ntoh16( + *((uint16_t*) (buffer + (of13::OFP_OXM_HEADER_LEN + len)))); + } + return 0; +} + +Match::Match() { + //: oxm_tlvs_(OXM_NUM) { + this->type_ = of13::OFPMT_OXM; + this->length_ = sizeof(struct of13::ofp_match) - 4; + memset(oxm_tlvs_, 0, sizeof(oxm_tlvs_)); +} + +Match::Match(const Match &match) { + this->type_ = match.type_; + this->length_ = 4; + memset(oxm_tlvs_, 0, sizeof(oxm_tlvs_)); + //this->oxm_tlvs_.reserve(OXM_NUM); + for (std::vector::const_iterator it = match.curr_tlvs_.begin(); + it != match.curr_tlvs_.end(); ++it) { + this->curr_tlvs_.push_back((*it)); + this->oxm_tlvs_[*it] = match.oxm_tlvs_[*it]->clone(); + this->length_ += of13::OFP_OXM_HEADER_LEN + + this->oxm_tlvs_[*it]->length(); + } +} + +Match& Match::operator=(Match other) { + swap(*this, other); + return *this; +} + +void Match::swap(Match& first, Match& second) { + std::swap(first.type_, second.type_); + std::swap(first.length_, second.length_); + std::swap(first.oxm_tlvs_, second.oxm_tlvs_); + std::swap(first.curr_tlvs_, second.curr_tlvs_); +} + +Match::~Match() { + for (std::vector::iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + delete this->oxm_tlvs_[*it]; + } +} + +OXMTLV * Match::make_oxm_tlv(uint8_t field) { + switch (field) { + case (of13::OFPXMT_OFB_IN_PORT): { + return new InPort(); + } + case (of13::OFPXMT_OFB_IN_PHY_PORT): { + return new InPhyPort(); + } + case (of13::OFPXMT_OFB_METADATA): { + return new Metadata(); + } + case (of13::OFPXMT_OFB_ETH_SRC): { + return new EthSrc(); + } + case (of13::OFPXMT_OFB_ETH_DST): { + return new EthDst(); + } + case (of13::OFPXMT_OFB_ETH_TYPE): { + return new EthType(); + } + case (of13::OFPXMT_OFB_VLAN_VID): { + return new VLANVid(); + } + case (of13::OFPXMT_OFB_VLAN_PCP): { + return new VLANPcp(); + } + case (of13::OFPXMT_OFB_IP_DSCP): { + return new IPDSCP(); + } + case (of13::OFPXMT_OFB_IP_ECN): { + return new IPECN(); + } + case (of13::OFPXMT_OFB_IP_PROTO): { + return new IPProto(); + } + case (of13::OFPXMT_OFB_IPV4_SRC): { + return new IPv4Src(); + } + case (of13::OFPXMT_OFB_IPV4_DST): { + return new IPv4Dst(); + } + case (of13::OFPXMT_OFB_TCP_SRC): { + return new TCPSrc(); + } + case (of13::OFPXMT_OFB_TCP_DST): { + return new TCPDst(); + } + case (of13::OFPXMT_OFB_UDP_SRC): { + return new UDPSrc(); + } + case (of13::OFPXMT_OFB_UDP_DST): { + return new UDPDst(); + } + case (of13::OFPXMT_OFB_SCTP_SRC): { + return new SCTPSrc(); + } + case (of13::OFPXMT_OFB_SCTP_DST): { + return new SCTPDst(); + } + case (of13::OFPXMT_OFB_ICMPV4_TYPE): { + return new ICMPv4Type(); + } + case (of13::OFPXMT_OFB_ICMPV4_CODE): { + return new ICMPv4Code(); + } + case (of13::OFPXMT_OFB_ARP_OP): { + return new ARPOp(); + } + case (of13::OFPXMT_OFB_ARP_SPA): { + return new ARPSPA(); + } + case (of13::OFPXMT_OFB_ARP_TPA): { + return new ARPTPA(); + } + case (of13::OFPXMT_OFB_ARP_SHA): { + return new ARPSHA(); + } + case (of13::OFPXMT_OFB_ARP_THA): { + return new ARPTHA(); + } + case (of13::OFPXMT_OFB_IPV6_SRC): { + return new IPv6Src(); + } + case (of13::OFPXMT_OFB_IPV6_DST): { + return new IPv6Dst(); + } + case (of13::OFPXMT_OFB_IPV6_FLABEL): { + return new IPV6Flabel(); + } + case (of13::OFPXMT_OFB_ICMPV6_TYPE): { + return new ICMPv6Type(); + } + case (of13::OFPXMT_OFB_ICMPV6_CODE): { + return new ICMPv6Code(); + } + case (of13::OFPXMT_OFB_IPV6_ND_TARGET): { + return new IPv6NDTarget(); + } + case (of13::OFPXMT_OFB_IPV6_ND_SLL): { + return new IPv6NDSLL(); + } + case (of13::OFPXMT_OFB_IPV6_ND_TLL): { + return new IPv6NDTLL(); + } + case (of13::OFPXMT_OFB_MPLS_LABEL): { + return new MPLSLabel(); + } + case (of13::OFPXMT_OFB_MPLS_TC): { + return new MPLSTC(); + } + case (of13::OFPXMT_OFB_MPLS_BOS): { + return new MPLSBOS(); + } + case (of13::OFPXMT_OFB_PBB_ISID): { + return new PBBIsid(); + } + case (of13::OFPXMT_OFB_TUNNEL_ID): { + return new TUNNELId(); + } + case (of13::OFPXMT_OFB_IPV6_EXTHDR): { + return new IPv6Exthdr(); + } + } + return NULL; +} + +bool Match::operator==(const Match &other) const { + for (std::vector::const_iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + OXMTLV *tlv1 = this->oxm_tlvs_[*it]; + OXMTLV *tlv2 = other.oxm_tlvs_[*it]; + if (tlv2) { + if (!tlv1->equals(*tlv2)) { + return false; + } + } + else { + return false; + } + } + return MatchHeader::operator==(other); +} + +bool Match::operator!=(const Match &other) const { + return !(*this == other); +} + +size_t Match::pack(uint8_t *buffer) { + MatchHeader::pack(buffer); + uint8_t *p = buffer + (sizeof(struct of13::ofp_match) - 4); + std::sort(this->curr_tlvs_.begin(), this->curr_tlvs_.end()); + for (std::vector::iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + this->oxm_tlvs_[*it]->pack(p); + p += of13::OFP_OXM_HEADER_LEN + this->oxm_tlvs_[*it]->length(); + } + return 0; +} + +of_error Match::unpack(uint8_t *buffer) { + MatchHeader::unpack(buffer); + size_t len = this->length_ - (sizeof(struct of13::ofp_match) - 4); + uint8_t * p = buffer + (sizeof(struct of13::ofp_match) - 4); + OXMTLV *oxm_tlv; + while (len) { + uint32_t header = ntoh32(*((uint32_t*) p)); + oxm_tlv = make_oxm_tlv(oxm_tlv->oxm_field(header)); + if (!oxm_tlv) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); + } + oxm_tlv->unpack(p); + if (check_dup(oxm_tlv)) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_DUP_FIELD); + } + if (!check_pre_req(oxm_tlv)) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_PREREQ); + } + this->curr_tlvs_.push_back(oxm_tlv->field()); + this->oxm_tlvs_[oxm_tlv->field()] = oxm_tlv; + len -= of13::OFP_OXM_HEADER_LEN + oxm_tlv->length(); + p += of13::OFP_OXM_HEADER_LEN + oxm_tlv->length(); + } + if (len) { + return openflow_error(OFPET_BAD_MATCH, OFPBMC_BAD_LEN); + } + return 0; +} + +OXMTLV * Match::oxm_field(uint8_t field) { + return this->oxm_tlvs_[field]; +} + +bool Match::check_pre_req(OXMTLV *tlv) { + /*Check ICMP type*/ + struct oxm_req r = tlv->oxm_reqs(); + if (r.icmp_req) { + ICMPv6Type *icmp_type = icmpv6_type(); + if (icmp_type) { + if (icmp_type->value() != r.icmp_req) { + return false; + } + } + else { + return false; + } + } + if (r.ip_proto_req) { + IPProto *proto = ip_proto(); + if (proto) { + if (proto->value() != r.ip_proto_req) { + return false; + } + } + else { + return false; + } + } + + /* Check for eth_type */ + if (!r.eth_type_req[0]) { + return true; + } + else { + EthType *type = eth_type(); + if (type) { + if (type->value() == r.eth_type_req[0]) { + return true; + } + else if (r.eth_type_req[1] && type->value() == r.eth_type_req[1]) { + return true; + } + } + else { + return false; + } + } + return false; +} + +bool Match::check_dup(OXMTLV *tlv) { + if (this->oxm_tlvs_[tlv->field()]) { + return true; + } + return false; +} + +void Match::add_oxm_field(OXMTLV &tlv) { + if (check_dup(&tlv)) return; + this->curr_tlvs_.push_back(tlv.field()); + this->oxm_tlvs_[tlv.field()] = tlv.clone(); + this->length_ += of13::OFP_OXM_HEADER_LEN + tlv.length(); +} + +void Match::add_oxm_field(OXMTLV* tlv) { + if (check_dup(tlv)) return; + this->curr_tlvs_.push_back(tlv->field()); + this->oxm_tlvs_[tlv->field()] = tlv; + this->length_ += of13::OFP_OXM_HEADER_LEN + tlv->length(); +} + +InPort* Match::in_port() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IN_PORT)); +} + +InPhyPort* Match::in_phy_port() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IN_PHY_PORT)); +} + +Metadata* Match::metadata() { + return static_cast(oxm_field(of13::OFPXMT_OFB_METADATA)); +} + +EthSrc* Match::eth_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_SRC)); +} + +EthDst* Match::eth_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_DST)); +} + +EthType* Match::eth_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ETH_TYPE)); +} + +VLANVid* Match::vlan_vid() { + return static_cast(oxm_field(of13::OFPXMT_OFB_VLAN_VID)); +} + +VLANPcp* Match::vlan_pcp() { + return static_cast(oxm_field(of13::OFPXMT_OFB_VLAN_PCP)); +} + +IPDSCP* Match::ip_dscp() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_DSCP)); +} + +IPECN* Match::ip_ecn() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_ECN)); +} + +IPProto* Match::ip_proto() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IP_PROTO)); +} + +IPv4Src* Match::ipv4_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV4_SRC)); +} + +IPv4Dst* Match::ipv4_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV4_DST)); +} + +TCPSrc* Match::tcp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TCP_SRC)); +} + +TCPDst* Match::tcp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TCP_DST)); +} + +UDPSrc* Match::udp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_UDP_SRC)); +} + +UDPDst* Match::udp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_UDP_DST)); +} + +SCTPSrc* Match::sctp_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_SCTP_SRC)); +} + +SCTPDst* Match::sctp_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_SCTP_DST)); +} + +ICMPv4Type* Match::icmpv4_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV4_TYPE)); +} + +ICMPv4Code* Match::icmpv4_code() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV4_CODE)); +} + +ARPOp* Match::arp_op() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_OP)); +} + +ARPSPA* Match::arp_spa() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_SPA)); +} + +ARPTPA* Match::arp_tpa() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_TPA)); +} + +ARPSHA* Match::arp_sha() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_SHA)); +} + +ARPTHA* Match::arp_tha() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ARP_THA)); +} + +IPv6Src* Match::ipv6_src() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_SRC)); +} + +IPv6Dst* Match::ipv6_dst() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_DST)); +} + +IPV6Flabel* Match::ipv6_flabel() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_FLABEL)); +} + +ICMPv6Type* Match::icmpv6_type() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV6_TYPE)); +} + +ICMPv6Code* Match::icmpv6_code() { + return static_cast(oxm_field(of13::OFPXMT_OFB_ICMPV6_CODE)); +} + +IPv6NDTarget* Match::ipv6_nd_target() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_TARGET)); +} + +IPv6NDSLL* Match::ipv6_nd_sll() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_SLL)); +} + +IPv6NDTLL* Match::ipv6_nd_tll() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_ND_TLL)); +} + +MPLSLabel* Match::mpls_label() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_LABEL)); +} + +MPLSTC* Match::mpls_tc() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_TC)); +} + +MPLSBOS* Match::mpls_bos() { + return static_cast(oxm_field(of13::OFPXMT_OFB_MPLS_BOS)); +} + +PBBIsid* Match::pbb_isid() { + return static_cast(oxm_field(of13::OFPXMT_OFB_PBB_ISID)); +} + +TUNNELId* Match::tunnel_id() { + return static_cast(oxm_field(of13::OFPXMT_OFB_TUNNEL_ID)); +} + +IPv6Exthdr* Match::ipv6_exthdr() { + return static_cast(oxm_field(of13::OFPXMT_OFB_IPV6_EXTHDR)); +} + +uint16_t Match::oxm_fields_len() { + uint16_t len = 0; + for (std::vector::const_iterator it = this->curr_tlvs_.begin(); + it != this->curr_tlvs_.end(); ++it) { + len += of13::OFP_OXM_HEADER_LEN + this->oxm_tlvs_[*it]->length(); + } + return len; +} + +} //End of namespace of13 +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/of13/of13meter.cc b/src/ovs/libfluid-msg/of13/of13meter.cc new file mode 100644 index 00000000..0f6d3353 --- /dev/null +++ b/src/ovs/libfluid-msg/of13/of13meter.cc @@ -0,0 +1,492 @@ +#include "libfluid-msg/util/util.h" +#include "libfluid-msg/of13/of13meter.hh" + +namespace fluid_msg { + +namespace of13 { + +MeterBand::MeterBand() + : type_(0), + rate_(0), + burst_size_(0), + len_(sizeof(struct of13::ofp_meter_band_header)) { + +} + +MeterBand::MeterBand(uint16_t type, uint32_t rate, uint32_t burst_size) + : type_(type), + rate_(rate), + burst_size_(burst_size), + len_(sizeof(struct of13::ofp_meter_band_header)) { +} + +bool MeterBand::equals(const MeterBand &other) { + return ((this->type_ == other.type_) && (this->rate_ == other.rate_) + && (this->burst_size_ == other.burst_size_)); +} + +size_t MeterBand::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_header *bh = + (struct of13::ofp_meter_band_header *) buffer; + bh->type = hton16(this->type_); + bh->len = hton16(this->len_); + bh->rate = hton32(this->rate_); + bh->burst_size = hton32(this->burst_size_); + return this->len_; +} + +of_error MeterBand::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_header *bh = + (struct of13::ofp_meter_band_header *) buffer; + this->type_ = hton16(bh->type); + this->len_ = hton16(bh->len); + this->rate_ = hton32(bh->rate); + this->burst_size_ = hton32(bh->burst_size); + return 0; +} + +MeterBand * MeterBand::make_meter_band(uint16_t type) { + switch (type) { + case (of13::OFPMBT_DROP): { + return new MeterBandDrop(); + } + case (of13::OFPMBT_DSCP_REMARK): { + return new MeterBandDSCPRemark(); + } + case (of13::OFPMBT_EXPERIMENTER): { + return new MeterBandExperimenter(); + } + } + return NULL; +} + +MeterBandList::MeterBandList(std::list band_list) { + this->band_list_ = band_list_; + for (std::list::const_iterator it = band_list.begin(); + it != band_list.end(); ++it) { + this->length_ += (*it)->len(); + } +} + +MeterBandList::MeterBandList(const MeterBandList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = other.band_list_.begin(); + it != other.band_list_.end(); ++it) { + this->band_list_.push_back((*it)->clone()); + } +} + +MeterBandList::~MeterBandList() { + this->band_list_.remove_if(MeterBand::delete_all); +} + +bool MeterBandList::operator==(const MeterBandList &other) const { + std::list::const_iterator ot = other.band_list_.begin(); + for (std::list::const_iterator it = this->band_list_.begin(); + it != this->band_list_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool MeterBandList::operator!=(const MeterBandList &other) const { + return !(*this == other); +} + +size_t MeterBandList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->band_list_.begin(), end = + this->band_list_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->len(); + } + return 0; +} + +of_error MeterBandList::unpack(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + MeterBand *band; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + band = MeterBand::make_meter_band(type); + band->unpack(p); + this->band_list_.push_back(band); + len -= band->len(); + p += band->len(); + } + return 0; +} + +MeterBandList& MeterBandList::operator=(MeterBandList other) { + swap(*this, other); + return *this; +} + +void swap(MeterBandList& first, MeterBandList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.band_list_, second.band_list_); +} + +void MeterBandList::add_band(MeterBand *band) { + this->band_list_.push_back(band); + this->length_ += band->len(); +} + +MeterBandDrop::MeterBandDrop() + : MeterBand(of13::OFPMBT_DROP, 0, 0) { + this->len_ = sizeof(struct of13::ofp_meter_band_drop); +} + +MeterBandDrop::MeterBandDrop(uint32_t rate, uint32_t burst_size) + : MeterBand(of13::OFPMBT_DROP, rate, burst_size) { + this->len_ = sizeof(struct of13::ofp_meter_band_drop); +} + +size_t MeterBandDrop::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_drop *bd = + (struct of13::ofp_meter_band_drop*) buffer; + MeterBand::pack(buffer); + memset(bd->pad, 0x0, 4); + return this->len_; +} + +of_error MeterBandDrop::unpack(uint8_t* buffer) { + MeterBand::unpack(buffer); + return 0; +} + +MeterBandDSCPRemark::MeterBandDSCPRemark() + : MeterBand(of13::OFPMBT_DSCP_REMARK, 0, 0), + prec_level_(0) { + this->len_ = sizeof(struct of13::ofp_meter_band_dscp_remark); +} + +MeterBandDSCPRemark::MeterBandDSCPRemark(uint32_t rate, uint32_t burst_size, + uint8_t prec_level) + : MeterBand(of13::OFPMBT_DSCP_REMARK, rate, burst_size) { + this->prec_level_ = prec_level; + this->len_ = sizeof(struct of13::ofp_meter_band_dscp_remark); +} + +bool MeterBandDSCPRemark::equals(const MeterBand &other) { + + if (const MeterBandDSCPRemark * band = + dynamic_cast(&other)) { + return ((MeterBand::equals(other)) + && (this->prec_level_ == band->prec_level_)); + } + else { + return false; + } +} + +size_t MeterBandDSCPRemark::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_dscp_remark *bd = + (struct of13::ofp_meter_band_dscp_remark*) buffer; + MeterBand::pack(buffer); + bd->prec_level = this->prec_level_; + memset(bd->pad, 0x0, 3); + return this->len_; +} + +of_error MeterBandDSCPRemark::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_dscp_remark *bd = + (struct of13::ofp_meter_band_dscp_remark*) buffer; + MeterBand::unpack(buffer); + this->prec_level_ = bd->prec_level; + return 0; +} + +MeterBandExperimenter::MeterBandExperimenter() + : experimenter_(0) { + this->len_ = sizeof(struct of13::ofp_meter_band_experimenter); +} + +MeterBandExperimenter::MeterBandExperimenter(uint32_t rate, uint32_t burst_size, + uint32_t experimenter) + : MeterBand(of13::OFPMBT_EXPERIMENTER, rate, burst_size) { + this->experimenter_ = experimenter; + this->len_ = sizeof(struct of13::ofp_meter_band_experimenter); +} + +bool MeterBandExperimenter::equals(const MeterBand &other) { + + if (const MeterBandExperimenter * band = + dynamic_cast(&other)) { + return ((MeterBand::equals(other)) + && (this->experimenter_ == band->experimenter_)); + } + else { + return false; + } +} + +size_t MeterBandExperimenter::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_experimenter *be = + (struct of13::ofp_meter_band_experimenter*) buffer; + MeterBand::pack(buffer); + be->experimenter = hton32(this->experimenter_); + return this->len_; +} + +of_error MeterBandExperimenter::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_experimenter *be = + (struct of13::ofp_meter_band_experimenter*) buffer; + MeterBand::unpack(buffer); + this->experimenter_ = ntoh32(be->experimenter); + return 0; +} + +MeterConfig::MeterConfig() + : flags_(0), + meter_id_(0), + length_(sizeof(struct of13::ofp_meter_config)) { +} + +MeterConfig::MeterConfig(uint16_t flags, uint32_t meter_id) + : flags_(flags), + meter_id_(meter_id), + length_(sizeof(struct of13::ofp_meter_config)) { +} + +MeterConfig::MeterConfig(uint16_t flags, uint32_t meter_id, MeterBandList bands) + : bands_(bands) { + this->flags_ = flags; + this->meter_id_ = meter_id; + this->length_ = sizeof(struct of13::ofp_meter_config) + bands.length(); +} + +bool MeterConfig::operator==(const MeterConfig &other) const { + return ((this->flags_ == other.flags_) + && (this->meter_id_ == other.meter_id_) + && (this->bands_ == other.bands_)); +} + +bool MeterConfig::operator!=(const MeterConfig &other) const { + return !(*this == other); +} + +size_t MeterConfig::pack(uint8_t* buffer) { + struct of13::ofp_meter_config *mc = (struct of13::ofp_meter_config*) buffer; + mc->length = hton16(this->length_); + mc->flags = hton16(this->flags_); + mc->meter_id = hton32(this->meter_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_config); + this->bands_.pack(p); + return this->length_; +} + +of_error MeterConfig::unpack(uint8_t* buffer) { + struct of13::ofp_meter_config *mc = (struct of13::ofp_meter_config *) buffer; + this->length_ = ntoh16(mc->length); + this->flags_ = ntoh16(mc->flags); + this->meter_id_ = ntoh32(mc->meter_id); + this->bands_.length(this->length_ - sizeof(struct of13::ofp_meter_config)); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_config); + this->bands_.unpack(p); + return 0; +} + +void MeterConfig::bands(MeterBandList bands) { + this->bands_ = bands; + this->length_ += bands.length(); +} + +void MeterConfig::add_band(MeterBand* band) { + this->bands_.add_band(band); + this->length_ += band->len(); +} + +MeterFeatures::MeterFeatures() + : max_meter_(0), + band_types_(0), + capabilities_(0), + max_bands_(0), + max_color_(0) { + +} + +MeterFeatures::MeterFeatures(uint32_t max_meter, uint32_t band_types, + uint32_t capabilities, uint8_t max_bands, uint8_t max_color) + : max_meter_(max_meter), + band_types_(band_types), + capabilities_(capabilities), + max_bands_(max_bands), + max_color_(max_color) { +} + +bool MeterFeatures::operator==(const MeterFeatures &other) const { + return ((this->max_meter_ == other.max_meter_) + && (this->band_types_ == other.band_types_) + && (this->capabilities_ == other.capabilities_) + && (this->max_bands_ == other.max_bands_) + && (this->max_color_ == other.max_color_)); +} + +bool MeterFeatures::operator!=(const MeterFeatures &other) const { + return !(*this == other); +} + +size_t MeterFeatures::pack(uint8_t* buffer) { + struct of13::ofp_meter_features *mf = + (struct of13::ofp_meter_features *) buffer; + mf->max_meter = hton32(this->max_meter_); + mf->band_types = hton32(this->band_types_); + mf->capabilities = hton32(this->capabilities_); + mf->max_bands = this->max_bands_; + mf->max_color = this->max_color_; + memset(mf->pad, 0x0, 2); + return 0; +} + +of_error MeterFeatures::unpack(uint8_t* buffer) { + struct of13::ofp_meter_features *mf = + (struct of13::ofp_meter_features *) buffer; + this->max_meter_ = ntoh32(mf->max_meter); + this->band_types_ = ntoh32(mf->band_types); + this->capabilities_ = ntoh32(mf->capabilities); + this->max_bands_ = mf->max_bands; + this->max_color_ = mf->max_color; + return 0; +} + +BandStats::BandStats() + : packet_band_count_(0), + byte_band_count_(0) { +} + +BandStats::BandStats(uint64_t packet_band_count, uint64_t byte_band_count) { + this->packet_band_count_ = packet_band_count; + this->byte_band_count_ = byte_band_count; +} + +bool BandStats::operator==(const BandStats &other) const { + return ((this->packet_band_count_ == other.packet_band_count_) + && (this->byte_band_count_ == other.byte_band_count_)); +} + +bool BandStats::operator!=(const BandStats &other) const { + return !(*this == other); +} + +size_t BandStats::pack(uint8_t* buffer) { + struct of13::ofp_meter_band_stats *mb = + (struct of13::ofp_meter_band_stats *) buffer; + mb->packet_band_count = hton64(this->packet_band_count_); + mb->byte_band_count = hton64(this->byte_band_count_); + return 0; +} + +of_error BandStats::unpack(uint8_t* buffer) { + struct of13::ofp_meter_band_stats *mb = + (struct of13::ofp_meter_band_stats *) buffer; + this->packet_band_count_ = ntoh64(mb->packet_band_count); + this->byte_band_count_ = ntoh64(mb->byte_band_count); + return 0; +} + +MeterStats::MeterStats() + : meter_id_(0), + flow_count_(0), + packet_in_count_(0), + byte_in_count_(0), + duration_sec_(0), + duration_nsec_(0), + len_(sizeof(struct of13::ofp_meter_stats)) { + +} + +MeterStats::MeterStats(uint32_t meter_id, uint32_t flow_count, + uint64_t packet_in_count, uint64_t byte_in_count, uint32_t duration_sec, + uint32_t duration_nsec) + : meter_id_(meter_id), + flow_count_(flow_count), + packet_in_count_(packet_in_count), + byte_in_count_(byte_in_count), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + len_(sizeof(struct of13::ofp_meter_stats)) { +} + +MeterStats::MeterStats(uint32_t meter_id, uint32_t flow_count, + uint64_t packet_in_count, uint64_t byte_in_count, uint32_t duration_sec, + uint32_t duration_nsec, std::vector band_stats) { + this->meter_id_ = meter_id; + this->flow_count_ = flow_count; + this->packet_in_count_ = packet_in_count; + this->byte_in_count_ = byte_in_count; + this->duration_sec_ = duration_sec; + this->duration_nsec_ = duration_nsec; + this->len_ = sizeof(struct of13::ofp_meter_stats) + + band_stats.size() * sizeof(struct of13::ofp_meter_band_stats); +} + +bool MeterStats::operator==(const MeterStats &other) const { + return ((this->meter_id_ == other.meter_id_) + && (this->flow_count_ == other.flow_count_) + && (this->packet_in_count_ == other.packet_in_count_) + && (this->byte_in_count_ == other.byte_in_count_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_)); +} + +bool MeterStats::operator!=(const MeterStats &other) const { + return !(*this == other); +} + +size_t MeterStats::pack(uint8_t* buffer) { + struct of13::ofp_meter_stats *ms = (struct of13::ofp_meter_stats*) buffer; + ms->meter_id = hton32(this->meter_id_); + ms->len = hton16(this->len_); + ms->flow_count = hton32(this->flow_count_); + ms->packet_in_count = hton64(this->packet_in_count_); + ms->byte_in_count = hton64(this->byte_in_count_); + ms->duration_sec = hton32(this->duration_sec_); + ms->duration_nsec = hton32(this->duration_nsec_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_stats); + for (std::vector::iterator it = this->band_stats_.begin(); + it != this->band_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_meter_band_stats); + } + return 0; +} + +of_error MeterStats::unpack(uint8_t* buffer) { + struct of13::ofp_meter_stats *ms = (struct of13::ofp_meter_stats*) buffer; + this->meter_id_ = ntoh32(ms->meter_id); + this->len_ = ntoh16(ms->len); + this->flow_count_ = hton32(ms->flow_count); + this->packet_in_count_ = ntoh64(ms->packet_in_count); + this->byte_in_count_ = ntoh64(ms->byte_in_count); + this->duration_sec_ = ntoh32(ms->duration_sec); + this->duration_nsec_ = ntoh32(ms->duration_nsec); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_stats); + size_t len = this->len_ - sizeof(struct of13::ofp_meter_stats); + while (len) { + BandStats stats; + stats.unpack(p); + this->band_stats_.push_back(stats); + p += sizeof(struct of13::ofp_meter_band_stats); + len -= sizeof(struct of13::ofp_meter_band_stats); + } + return 0; +} + +void MeterStats::band_stats(std::vector band_stats) { + this->band_stats_ = band_stats; + this->len_ += band_stats.size() * sizeof(struct of13::ofp_meter_band_stats); +} + +void MeterStats::add_band_stats(BandStats stats) { + this->band_stats_.push_back(stats); + this->len_ += sizeof(struct of13::ofp_meter_band_stats); +} + +} //End of namespace fluid_msg + +} diff --git a/src/ovs/libfluid-msg/of13msg.cc b/src/ovs/libfluid-msg/of13msg.cc new file mode 100644 index 00000000..83cd61ae --- /dev/null +++ b/src/ovs/libfluid-msg/of13msg.cc @@ -0,0 +1,2940 @@ +#include "libfluid-msg/of13msg.hh" + +namespace fluid_msg { + +RoleCommon::RoleCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + role_(0), + generation_id_(0) { +} + +RoleCommon::RoleCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t role, uint64_t generation_id) + : OFMsg(version, type, xid), + role_(role), + generation_id_(generation_id) { + this->length_ = sizeof(struct ofp_role_request); +} + +bool RoleCommon::operator==(const RoleCommon &other) const { + return ((OFMsg::operator==(other)) && (this->role_ == other.role_) + && (this->generation_id_ == other.generation_id_) + && (this->length_ == other.length_)); +} + +bool RoleCommon::operator!=(const RoleCommon &other) const { + return !(*this == other); +} + +uint8_t* RoleCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_role_request * rq = (struct ofp_role_request*) buffer; + rq->role = hton32(this->role_); + memset(rq->pad, 0x0, 4); + rq->generation_id = hton64(this->generation_id_); + return buffer; +} + +of_error RoleCommon::unpack(uint8_t *buffer) { + struct ofp_role_request * rq = (struct ofp_role_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_role_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->role_ = ntoh32(rq->role); + memset(rq->pad, 0x0, 4); + this->generation_id_ = ntoh64(rq->generation_id); + return 0; +} + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + packet_in_mask_(2, 0), + port_status_mask_(2, 0), + flow_removed_mask_(2, 0) { +} + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type, + uint32_t xid) + : OFMsg(version, type, xid), + packet_in_mask_(2, 0), + port_status_mask_(2, 0), + flow_removed_mask_(2, 0) { + this->length_ = sizeof(struct ofp_async_config); +} +; + +AsyncConfigCommon::AsyncConfigCommon(uint8_t version, uint8_t type, + uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : OFMsg(version, type, xid), + packet_in_mask_(packet_in_mask), + port_status_mask_(port_status_mask), + flow_removed_mask_(flow_removed_mask) { + this->length_ = sizeof(struct ofp_async_config); +} + +bool AsyncConfigCommon::operator==(const AsyncConfigCommon &other) const { + return ((OFMsg::operator==(other)) + && (this->packet_in_mask_ == other.packet_in_mask_) + && (this->port_status_mask_ == other.port_status_mask_) + && (this->flow_removed_mask_ == other.flow_removed_mask_)); +} + +bool AsyncConfigCommon::operator!=(const AsyncConfigCommon &other) const { + return !(*this == other); +} + +uint8_t* AsyncConfigCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_async_config *ar = (struct ofp_async_config *) buffer; + ar->packet_in_mask[0] = hton32(this->packet_in_mask_[0]); + ar->packet_in_mask[1] = hton32(this->packet_in_mask_[1]); + ar->port_status_mask[0] = hton32(this->port_status_mask_[0]); + ar->port_status_mask[1] = hton32(this->port_status_mask_[1]); + ar->flow_removed_mask[0] = hton32(this->flow_removed_mask_[0]); + ar->flow_removed_mask[1] = hton32(this->flow_removed_mask_[1]); + return buffer; +} + +of_error AsyncConfigCommon::unpack(uint8_t *buffer) { + struct ofp_async_config *ar = (struct ofp_async_config *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_async_config)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->packet_in_mask_[0] = ntoh32(ar->packet_in_mask[0]); + this->packet_in_mask_[1] = ntoh32(ar->packet_in_mask[1]); + this->port_status_mask_[0] = ntoh32(ar->port_status_mask[0]); + this->port_status_mask_[1] = ntoh32(ar->port_status_mask[1]); + this->flow_removed_mask_[0] = ntoh32(ar->flow_removed_mask[0]); + this->flow_removed_mask_[1] = ntoh32(ar->flow_removed_mask[1]); + return 0; +} + +namespace of13 { + +Hello::Hello() + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO) { +} + +Hello::Hello(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO, xid) { +} + +Hello::Hello(uint32_t xid, std::list elements) + : OFMsg(of13::OFP_VERSION, of13::OFPT_HELLO, xid), + elements_(elements) { + this->length_ += elements_len(); +} + +bool Hello::operator==(const Hello &other) const { + return ((OFMsg::operator==(other)) && (this->elements_ == other.elements_)); +} + +bool Hello::operator!=(const Hello &other) const { + return !(*this == other); +} + +uint8_t* Hello::pack() { + uint8_t* buffer = OFMsg::pack(); + uint8_t *p = buffer + sizeof(struct ofp_fluid_header); + for (std::list::iterator it = + this->elements_.begin(), end = this->elements_.end(); it != end; ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error Hello::unpack(uint8_t* buffer) { + OFMsg::unpack(buffer); + /*Unpack the Hello elements*/ + uint32_t len = this->length_ - sizeof(struct ofp_fluid_header); + uint8_t *p = buffer + sizeof(struct ofp_fluid_header); + while (len) { + HelloElemVersionBitmap he; + he.unpack(p); + len -= he.length(); + this->elements_.push_back(he); + p += he.length(); + } + return 0; +} + +void Hello::elements(std::list elements) { + this->elements_ = elements; + this->length_ += elements_len(); +} + +void Hello::add_element(HelloElemVersionBitmap element) { + this->elements_.push_back(element); + this->length_ += element.length(); + +} + +uint32_t Hello::elements_len() { + uint32_t len = 0; + for (std::list::iterator it = + this->elements_.begin(), end = this->elements_.end(); it != end; ++it) { + len += (*it).length(); + } + return len; +} + +Error::Error() + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code) + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR, xid, err_type, code) { +} + +Error::Error(uint32_t xid, uint16_t err_type, uint16_t code, uint8_t *data, + size_t data_len) + : ErrorCommon(of13::OFP_VERSION, of13::OFPT_ERROR, xid, err_type, code, + data, data_len) { +} + +EchoRequest::EchoRequest() + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REQUEST) { +} + +EchoRequest::EchoRequest(uint32_t xid) + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REQUEST, xid) { +} + +EchoReply::EchoReply() + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REPLY) { +} + +EchoReply::EchoReply(uint32_t xid) + : EchoCommon(of13::OFP_VERSION, of13::OFPT_ECHO_REPLY, xid) { +} + +Experimenter::Experimenter() + : OFMsg(of13::OFP_VERSION, of13::OFPT_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_header); +} + +Experimenter::Experimenter(uint32_t xid, uint32_t experimenter, + uint32_t exp_type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_EXPERIMENTER, xid), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_header); +} + +bool Experimenter::operator==(const Experimenter &other) const { + return ((Experimenter::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool Experimenter::operator!=(const Experimenter &other) const { + return !(*this == other); +} + +uint8_t* Experimenter::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_experimenter_header *em = + (struct of13::ofp_experimenter_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error Experimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_header *em = + (struct of13::ofp_experimenter_header*) buffer; + OFMsg::unpack(buffer); + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +FeaturesRequest::FeaturesRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_FEATURES_REQUEST) { +} + +FeaturesRequest::FeaturesRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_FEATURES_REQUEST, xid) { +} + +uint8_t* FeaturesRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + return buffer; +} + +of_error FeaturesRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +FeaturesReply::FeaturesReply() + : FeaturesReplyCommon(of13::OFP_VERSION, of13::OFPT_FEATURES_REPLY) { + this->length_ = sizeof(struct of13::ofp_switch_features); +} + +FeaturesReply::FeaturesReply(uint32_t xid, uint64_t datapath_id, + uint32_t n_buffers, uint8_t n_tables, uint8_t auxiliary_id, + uint32_t capabilities) + : FeaturesReplyCommon(of13::OFP_VERSION, of13::OFPT_FEATURES_REPLY, xid, + datapath_id, n_buffers, n_tables, capabilities), + auxiliary_id_(auxiliary_id) { + this->length_ = sizeof(struct of13::ofp_switch_features); +} + +bool FeaturesReply::operator==(const FeaturesReply &other) const { + return ((FeaturesReplyCommon::operator==(other)) + && (this->auxiliary_id_ == other.auxiliary_id_)); +} + +bool FeaturesReply::operator!=(const FeaturesReply &other) const { + return !(*this == other); +} + +uint8_t* FeaturesReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_switch_features *fr = + (struct of13::ofp_switch_features *) buffer; + fr->datapath_id = hton64(this->datapath_id_); + fr->n_buffers = hton32(this->n_buffers_); + fr->n_tables = this->n_tables_; + memset(fr->pad, 0x0, 2); + fr->auxiliary_id = this->auxiliary_id_; + fr->capabilities = hton32(this->capabilities_); + fr->reserved = 0; + return buffer; +} + +of_error FeaturesReply::unpack(uint8_t *buffer) { + struct of13::ofp_switch_features *fr = + (struct of13::ofp_switch_features *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_switch_features)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->datapath_id_ = ntoh64(fr->datapath_id); + this->n_buffers_ = ntoh32(fr->n_buffers); + this->n_tables_ = fr->n_tables; + memset(fr->pad, 0x0, 2); + this->auxiliary_id_ = fr->auxiliary_id; + this->capabilities_ = ntoh32(fr->capabilities); + return 0; +} + +GetConfigRequest::GetConfigRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REQUEST) { +} + +GetConfigRequest::GetConfigRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REQUEST, xid) { +} + +uint8_t* GetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + return buffer; +} + +of_error GetConfigRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +GetConfigReply::GetConfigReply() + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REPLY) { +} + +GetConfigReply::GetConfigReply(uint32_t xid, uint16_t flags, + uint16_t miss_send_len) + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_CONFIG_REPLY, xid, + flags, miss_send_len) { +} + +SetConfig::SetConfig() + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_CONFIG) { +} + +SetConfig::SetConfig(uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : SwitchConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_CONFIG, xid, flags, + miss_send_len) { +} + +PacketOut::PacketOut() + : PacketOutCommon(of13::OFP_VERSION, of13::OFPT_PACKET_OUT), + in_port_(0) { + this->length_ = sizeof(struct of13::ofp_packet_out); +} + +PacketOut::PacketOut(uint32_t xid, uint32_t buffer_id, uint32_t in_port) + : PacketOutCommon(of13::OFP_VERSION, of13::OFPT_PACKET_OUT, xid, buffer_id), + in_port_(in_port) { + this->length_ = sizeof(struct of13::ofp_packet_out); +} + +bool PacketOut::operator==(const PacketOut &other) const { + return ((PacketOutCommon::operator==(other)) + && (this->in_port_ == other.in_port_)); +} + +bool PacketOut::operator!=(const PacketOut &other) const { + return !(*this == other); +} + +uint8_t* PacketOut::pack() { + size_t data_size; + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_packet_out *po = (struct of13::ofp_packet_out*) buffer; + po->buffer_id = hton32(this->buffer_id_); + po->in_port = hton32(this->in_port_); + po->actions_len = hton16(this->actions_len_); + memset(po->pad, 0x0, 6); + this->actions_.pack(buffer + sizeof(struct of13::ofp_packet_out)); + data_size = this->length_ + - (sizeof(struct of13::ofp_packet_out) + this->actions_len_); + uint8_t *p = buffer + sizeof(struct of13::ofp_packet_out) + + this->actions_len_; + memcpy(p, this->data_, data_size); + return buffer; +} + +of_error PacketOut::unpack(uint8_t *buffer) { + struct of13::ofp_packet_out *po = (struct of13::ofp_packet_out*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_packet_out)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->buffer_id_ = ntoh32(po->buffer_id); + this->in_port_ = ntoh32(po->in_port); + this->actions_len_ = ntoh16(po->actions_len); + size_t len = this->actions_len_; + uint8_t * p = buffer + sizeof(struct of13::ofp_packet_out); + this->actions_.unpack13(p); + len = this->length_ + - (sizeof(struct of13::ofp_packet_out) + this->actions_len_); + /*Reuse p to calculate the packet data position */ + p = buffer + sizeof(struct of13::ofp_packet_out) + this->actions_len_; + if (len) { + this->data_ = new uint8_t[len]; + memcpy(this->data_, p, len); + } + return 0; +} + +PacketIn::PacketIn() + : PacketInCommon(of13::OFP_VERSION, of13::OFPT_PACKET_IN), + table_id_(0), + cookie_(0) { +} + +PacketIn::PacketIn(uint32_t xid, uint32_t buffer_id, uint16_t total_len, + uint8_t reason, uint8_t table_id, uint64_t cookie) + : PacketInCommon(of13::OFP_VERSION, of13::OFPT_PACKET_IN, xid, buffer_id, + total_len, reason), + table_id_(table_id), + cookie_(cookie) { +} + +uint16_t PacketIn::length() { + return sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + this->data_len_; +} + +bool PacketIn::operator==(const PacketIn &other) const { + return ((PacketInCommon::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->cookie_ == other.cookie_) && (this->match_ == other.match_)); +} + +bool PacketIn::operator!=(const PacketIn &other) const { + return !(*this == other); +} + +uint8_t* PacketIn::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_packet_in) - 4 + this->match_.length(), 8) + - (sizeof(struct of13::ofp_packet_in) - 4 + this->match_.length()); + struct of13::ofp_packet_in *pi = (struct of13::ofp_packet_in*) buffer; + pi->buffer_id = hton32(this->buffer_id_); + pi->total_len = hton16(this->total_len_); + pi->reason = this->reason_; + pi->table_id = this->table_id_; + pi->cookie = hton64(this->cookie_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += match_.length(); + memset(p, 0x0, padding); + p += padding; + memset(p, 0x0, 2); + memcpy(p + 2, this->data_, this->data_len_); + return buffer; +} + +of_error PacketIn::unpack(uint8_t *buffer) { + struct of13::ofp_packet_in *pi = (struct of13::ofp_packet_in*) buffer; + OFMsg::unpack(buffer); + this->buffer_id_ = ntoh32(pi->buffer_id); + this->total_len_ = ntoh16(pi->total_len); + this->reason_ = pi->reason; + this->table_id_ = pi->table_id; + this->cookie_ = ntoh64(pi->cookie); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + p += ROUND_UP(this->match_.length(), 8); + this->data_len_ = this->length_ + - (sizeof(struct of13::ofp_packet_in) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + 2); + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, p + 2, this->data_len_); + return 0; +} + +OXMTLV * PacketIn::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void PacketIn::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void PacketIn::add_oxm_field(OXMTLV *field) { + this->match_.add_oxm_field(field); +} + +FlowMod::FlowMod() + : FlowModCommon(of13::OFP_VERSION, of13::OFPT_FLOW_MOD), + instructions_(), + command_(0), + cookie_mask_(0), + table_id_(0), + out_port_(0), + out_group_(0) { +} + +FlowMod::FlowMod(uint32_t xid, uint64_t cookie, uint64_t cookie_mask, + uint8_t table_id, uint8_t command, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint32_t out_port, uint32_t out_group, uint16_t flags) + : FlowModCommon(of13::OFP_VERSION, of13::OFPT_FLOW_MOD, xid, cookie, + idle_timeout, hard_timeout, priority, buffer_id, flags), + instructions_(), + command_(command), + cookie_mask_(cookie_mask), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group) { + ; +} + +uint16_t FlowMod::length() { + return sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match) + + ROUND_UP(this->match_.length(), 8) + this->instructions_.length(); +} + +bool FlowMod::operator==(const FlowMod &other) const { + return ((FlowModCommon::operator==(other)) + && (this->command_ == other.command_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->instructions_ == other.instructions_)); +} + +bool FlowMod::operator!=(const FlowMod &other) const { + return !(*this == other); +} + +uint8_t* FlowMod::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP(this->match_.length(), 8) - this->match_.length(); + struct of13::ofp_flow_mod *fm = (struct of13::ofp_flow_mod*) buffer; + fm->cookie = hton64(this->cookie_); + fm->cookie_mask = hton64(this->cookie_mask_); + fm->table_id = this->table_id_; + fm->command = this->command_; + fm->idle_timeout = hton16(this->idle_timeout_); + fm->hard_timeout = hton16(this->hard_timeout_); + fm->priority = hton16(this->priority_); + fm->buffer_id = hton32(this->buffer_id_); + fm->out_port = hton32(this->out_port_); + fm->out_group = hton32(this->out_group_); + fm->flags = hton16(this->flags_); + memset(fm->pad, 0x0, 2); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + p += padding; + this->instructions_.pack(p); + return buffer; +} + +of_error FlowMod::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + of_error err; + struct of13::ofp_flow_mod *fm = (struct of13::ofp_flow_mod*) buffer; + if (this->length_ < sizeof(struct of13::ofp_flow_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->cookie_ = ntoh64(fm->cookie); + this->cookie_mask_ = ntoh64(fm->cookie_mask); + this->table_id_ = fm->table_id; + this->command_ = fm->command; + this->idle_timeout_ = ntoh16(fm->idle_timeout); + this->hard_timeout_ = ntoh16(fm->hard_timeout); + this->priority_ = ntoh16(fm->priority); + this->buffer_id_ = ntoh32(fm->buffer_id); + this->out_port_ = ntoh32(fm->out_port); + this->out_group_ = ntoh32(fm->out_group); + this->flags_ = ntoh16(fm->flags); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_mod) - sizeof(struct of13::ofp_match)); + err = this->match_.unpack(p); + if (err) { + return err; + } + this->instructions_.length( + this->length_ + - ((sizeof(struct of13::ofp_flow_mod) + - sizeof(struct of13::ofp_match)) + + ROUND_UP(this->match_.length(), 8))); + p += ROUND_UP(this->match_.length(), 8); + this->instructions_.unpack(p); + return 0; +} + +OXMTLV * FlowMod::get_oxm_field(uint8_t field) { + return this->match_.oxm_field(field); +} + +void FlowMod::match(of13::Match match) { + this->match_ = match; + this->length_ += this->match_.length(); +} + +void FlowMod::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void FlowMod::add_oxm_field(OXMTLV *field) { + this->match_.add_oxm_field(field); +} + +void FlowMod::instructions(InstructionSet instructions) { + this->instructions_ = instructions; + this->length_ += instructions.length(); +} + +void FlowMod::add_instruction(Instruction &inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst.length(); +} + +void FlowMod::add_instruction(Instruction* inst) { + this->instructions_.add_instruction(inst); + this->length_ += inst->length(); +} + +FlowRemoved::FlowRemoved() + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED), + table_id_(0), + hard_timeout_(0) { +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count) + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count), + table_id_(table_id), + hard_timeout_(hard_timeout) { +} + +FlowRemoved::FlowRemoved(uint32_t xid, uint64_t cookie, uint16_t priority, + uint8_t reason, uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t idle_timeout, uint16_t hard_timeout, + uint64_t packet_count, uint64_t byte_count, of13::Match match) + : FlowRemovedCommon(of13::OFP_VERSION, of13::OFPT_FLOW_REMOVED, xid, cookie, + priority, reason, duration_sec, duration_nsec, idle_timeout, + packet_count, byte_count) { + this->table_id_ = table_id; + this->hard_timeout_ = hard_timeout; + this->match_ = match; +} + +uint16_t FlowRemoved::length() { + return sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); +} + +bool FlowRemoved::operator==(const FlowRemoved &other) const { + return ((FlowRemovedCommon::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->match_ == other.match_)); +} + +bool FlowRemoved::operator!=(const FlowRemoved &other) const { + return !(*this == other); +} + +uint8_t* FlowRemoved::pack() { + this->length_ = length(); + uint8_t* buffer = OFMsg::pack(); + size_t padding = ROUND_UP(this->match_.length(), 8) - this->match_.length(); + struct of13::ofp_flow_removed *fr = (struct of13::ofp_flow_removed*) buffer; + fr->cookie = hton64(this->cookie_); + fr->priority = hton16(this->priority_); + fr->reason = this->reason_; + fr->table_id = this->table_id_; + fr->duration_sec = hton32(this->duration_sec_); + fr->duration_nsec = hton32(this->duration_nsec_); + fr->idle_timeout = hton16(this->idle_timeout_); + fr->hard_timeout = hton32(this->hard_timeout_); + fr->packet_count = hton64(this->packet_count_); + fr->byte_count = hton64(this->byte_count_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error FlowRemoved::unpack(uint8_t *buffer) { + struct of13::ofp_flow_removed *fr = (struct of13::ofp_flow_removed*) buffer; + OFMsg::unpack(buffer); + this->cookie_ = ntoh64(fr->cookie); + this->priority_ = ntoh16(fr->priority); + this->reason_ = fr->reason; + this->table_id_ = fr->table_id; + this->duration_sec_ = ntoh32(fr->duration_sec); + this->duration_nsec_ = ntoh32(fr->duration_nsec); + this->idle_timeout_ = ntoh16(fr->idle_timeout); + this->hard_timeout_ = ntoh32(fr->hard_timeout); + this->packet_count_ = ntoh64(fr->packet_count); + this->byte_count_ = ntoh64(fr->byte_count); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_flow_removed) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +PortStatus::PortStatus() + : PortStatusCommon(of13::OFP_VERSION, of13::OFPT_PORT_STATUS) { + this->length_ = sizeof(struct of13::ofp_port_status); +} + +PortStatus::PortStatus(uint32_t xid, uint8_t reason, of13::Port desc) + : PortStatusCommon(of13::OFP_VERSION, of13::OFPT_PORT_STATUS, xid, reason), + desc_(desc) { + this->length_ = sizeof(struct of13::ofp_port_status); +} + +bool PortStatus::operator==(const PortStatus &other) const { + return ((PortStatusCommon::operator==(other)) + && (this->desc_ == other.desc_)); +} + +bool PortStatus::operator!=(const PortStatus &other) const { + return !(*this == other); +} + +uint8_t* PortStatus::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_port_status *ps = (struct of13::ofp_port_status *) buffer; + ps->reason = this->reason_; + memset(ps->pad, 0x0, 7); + this->desc_.pack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return buffer; +} + +of_error PortStatus::unpack(uint8_t *buffer) { + struct of13::ofp_port_status *ps = (struct of13::ofp_port_status *) buffer; + OFMsg::unpack(buffer); + this->reason_ = ps->reason; + this->desc_.unpack(buffer + (sizeof(struct ofp_fluid_header) + 8)); + return 0; +} + +PortMod::PortMod() + : PortModCommon(of13::OFP_VERSION, of13::OFPT_PORT_MOD) { + this->length_ = sizeof(struct of13::ofp_port_mod); +} + +PortMod::PortMod(uint32_t xid, uint32_t port_no, EthAddress hw_addr, + uint32_t config, uint32_t mask, uint32_t advertise) + : PortModCommon(of13::OFP_VERSION, of13::OFPT_PORT_MOD, xid, hw_addr, + config, mask, advertise), + port_no_(port_no) { + this->length_ = sizeof(struct of13::ofp_port_mod); +} + +bool PortMod::operator==(const PortMod &other) const { + return ((PortModCommon::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool PortMod::operator!=(const PortMod &other) const { + return !(*this == other); +} + +uint8_t* PortMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_port_mod *pm = (struct of13::ofp_port_mod *) buffer; + pm->port_no = hton32(this->port_no_); + memset(pm->pad, 0x0, 4); + memcpy(pm->hw_addr, hw_addr_.get_data(), OFP_ETH_ALEN); + memset(pm->pad, 0x0, 2); + pm->config = hton32(this->config_); + pm->mask = hton32(this->mask_); + pm->advertise = hton32(this->advertise_); + memset(pm->pad, 0x0, 4); + return buffer; +} + +of_error PortMod::unpack(uint8_t* buffer) { + struct of13::ofp_port_mod *pm = (struct of13::ofp_port_mod *) buffer; + if (pm->header.length < sizeof(struct of13::ofp_port_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + OFMsg::unpack(buffer); + this->port_no_ = ntoh32(pm->port_no); + this->hw_addr_ = EthAddress(pm->hw_addr); + this->config_ = ntoh32(pm->config); + this->mask_ = ntoh32(pm->mask); + this->advertise_ = ntoh32(pm->advertise); + return 0; +} + +GroupMod::GroupMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD) { + this->length_ = sizeof(struct of13::ofp_group_mod); +} + +GroupMod::GroupMod(uint32_t xid, uint16_t command, uint8_t type, + uint32_t group_id) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD, xid), + command_(command), + group_type_(type), + group_id_(group_id) { + this->length_ = sizeof(struct of13::ofp_group_mod); +} + +GroupMod::GroupMod(uint32_t xid, uint16_t command, uint8_t type, + uint32_t group_id, std::vector buckets) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GROUP_MOD, xid) { + this->command_ = command; + this->group_type_ = type; + this->group_id_ = group_id; + this->buckets_ = buckets; + this->length_ = sizeof(struct of13::ofp_group_mod) + buckets_len(); +} + +bool GroupMod::operator==(const GroupMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) + && (this->group_type_ == other.group_type_) + && (this->group_id_ == other.group_id_) + && (this->buckets_ == other.buckets_)); +} + +bool GroupMod::operator!=(const GroupMod &other) const { + return !(*this == other); +} + +void GroupMod::buckets(std::vector buckets) { + this->buckets_ = buckets; + this->length_ += buckets_len(); +} + +void GroupMod::add_bucket(Bucket bucket) { + this->buckets_.push_back(bucket); + this->length_ += bucket.len(); +} + +size_t GroupMod::buckets_len() { + size_t len = 0; + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + len += it->len(); + } + return len; +} +; + +uint8_t* GroupMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_group_mod *gm = (struct of13::ofp_group_mod*) buffer; + gm->command = hton16(this->command_); + gm->type = this->group_type_; + gm->group_id = hton32(this->group_id_); + uint8_t *p = buffer + sizeof(struct ofp_group_mod); + for (std::vector::iterator it = this->buckets_.begin(); + it != this->buckets_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error GroupMod::unpack(uint8_t *buffer) { + struct of13::ofp_group_mod *gm = (struct of13::ofp_group_mod*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_group_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->command_ = ntoh16(gm->command); + this->group_type_ = gm->type; + this->group_id_ = ntoh32(gm->group_id); + size_t len = this->length_ - sizeof(struct ofp_group_mod); + uint8_t *p = buffer + sizeof(struct ofp_group_mod); + while (len) { + Bucket bucket; + bucket.unpack(p); + this->buckets_.push_back(bucket); + p += bucket.len(); + len -= bucket.len(); + } + return 0; +} + +TableMod::TableMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_TABLE_MOD) { + this->length_ = sizeof(struct of13::ofp_table_mod); +} + +TableMod::TableMod(uint32_t xid, uint8_t table_id, uint32_t config) + : OFMsg(of13::OFP_VERSION, of13::OFPT_TABLE_MOD, xid), + table_id_(table_id), + config_(config) { + this->length_ = sizeof(struct of13::ofp_table_mod); +} + +bool TableMod::operator==(const TableMod &other) const { + return ((OFMsg::operator==(other)) && (this->table_id_ == other.table_id_) + && (this->config_ == other.config_)); +} + +bool TableMod::operator!=(const TableMod &other) const { + return !(*this == other); +} + +uint8_t* TableMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_table_mod *tm = (struct of13::ofp_table_mod*) buffer; + tm->table_id = this->table_id_; + memset(tm->pad, 0x0, 3); + tm->config = hton32(this->config_); + return buffer; +} + +of_error TableMod::unpack(uint8_t *buffer) { + struct of13::ofp_table_mod *tm = (struct of13::ofp_table_mod*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_table_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = tm->table_id; + this->config_ = ntoh32(tm->config); + return 0; +} + +MultipartRequest::MultipartRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +MultipartRequest::MultipartRequest(uint16_t type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST), + mpart_type_(type) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +MultipartRequest::MultipartRequest(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REQUEST, xid), + mpart_type_(type), + flags_(flags) { + this->length_ = sizeof(struct of13::ofp_multipart_request); +} + +bool MultipartRequest::operator==(const MultipartRequest &other) const { + return ((OFMsg::operator==(other)) + && (this->mpart_type_ == other.mpart_type_) + && (this->length_ == other.length_)); +} + +bool MultipartRequest::operator!=(const MultipartRequest &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_multipart_request * mr = + (struct of13::ofp_multipart_request *) buffer; + mr->type = hton16(this->mpart_type_); + mr->flags = hton16(this->flags_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequest::unpack(uint8_t *buffer) { + struct of13::ofp_multipart_request * mr = + (struct of13::ofp_multipart_request *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->mpart_type_ = ntoh16(mr->type); + this->flags_ = ntoh16(mr->flags); + return 0; +} + +MultipartReply::MultipartReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY) { + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +MultipartReply::MultipartReply(uint16_t type) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY), + mpart_type_(type) { + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +MultipartReply::MultipartReply(uint32_t xid, uint16_t type, uint16_t flags) + : OFMsg(of13::OFP_VERSION, of13::OFPT_MULTIPART_REPLY, xid), + mpart_type_(type), + flags_(flags) { + this->mpart_type_ = type; + this->flags_ = flags; + this->length_ = sizeof(struct of13::ofp_multipart_reply); +} + +bool MultipartReply::operator==(const MultipartReply &other) const { + return ((OFMsg::operator==(other)) + && (this->mpart_type_ == other.mpart_type_) + && (this->flags_ == other.flags_)); +} + +bool MultipartReply::operator!=(const MultipartReply &other) const { + return !(*this == other); +} + +uint8_t* MultipartReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_multipart_reply * mr = + (struct of13::ofp_multipart_reply *) buffer; + mr->type = hton16(this->mpart_type_); + mr->flags = hton16(this->flags_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartReply::unpack(uint8_t *buffer) { + struct of13::ofp_multipart_reply * mr = + (struct of13::ofp_multipart_reply *) buffer; + OFMsg::unpack(buffer); + this->mpart_type_ = ntoh16(mr->type); + this->flags_ = ntoh16(mr->flags); + return 0; +} + +MultipartRequestDesc::MultipartRequestDesc() + : MultipartRequest(OFPMP_DESC) { +} + +MultipartRequestDesc::MultipartRequestDesc(uint32_t xid, uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_DESC, flags) { +} + +uint8_t* MultipartRequestDesc::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestDesc::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyDesc::MultipartReplyDesc() + : MultipartReply(of13::OFPMP_DESC) { + this->length_ += sizeof(struct ofp_desc); +} + +MultipartReplyDesc::MultipartReplyDesc(uint32_t xid, uint16_t flags, + SwitchDesc desc) + : MultipartReply(xid, of13::OFPMP_DESC, flags) { + this->desc_ = desc; + this->length_ += sizeof(struct ofp_desc); +} + +MultipartReplyDesc::MultipartReplyDesc(uint32_t xid, uint16_t flags, + std::string mfr_desc, std::string hw_desc, std::string sw_desc, + std::string serial_num, std::string dp_desc) + : MultipartReply(xid, of13::OFPMP_DESC, flags), + desc_(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) { + + this->length_ += sizeof(struct ofp_desc); +} + +bool MultipartReplyDesc::operator==(const MultipartReplyDesc &other) const { + return ((MultipartReply::operator==(other)) && (this->desc_ == other.desc_)); +} + +bool MultipartReplyDesc::operator!=(const MultipartReplyDesc &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyDesc::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->desc_.pack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyDesc::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->desc_.unpack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestFlow::MultipartRequestFlow() + : MultipartRequest(OFPMP_FLOW) { + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestFlow::MultipartRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask) + : MultipartRequest(xid, of13::OFPMP_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask) { + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestFlow::MultipartRequestFlow(uint32_t xid, uint16_t flags, + uint8_t table_id, uint32_t out_port, uint32_t out_group, uint64_t cookie, + uint64_t cookie_mask, of13::Match match) + : MultipartRequest(xid, of13::OFPMP_FLOW, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask), + match_(match) { + + this->length_ += sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + match.length(); +} + +bool MultipartRequestFlow::operator==(const MultipartRequestFlow &other) const { + return ((MultipartRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->cookie_ == other.cookie_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->match_ == other.match_)); +} + +bool MultipartRequestFlow::operator!=(const MultipartRequestFlow &other) const { + return !(*this == other); +} + +void MultipartRequestFlow::match(of13::Match match) { + this->match_ = match; + this->length_ += match.length(); +} + +void MultipartRequestFlow::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void MultipartRequestFlow::add_oxm_field(OXMTLV* field) { + this->match_.add_oxm_field(field); +} + +uint8_t* MultipartRequestFlow::pack() { + size_t padding = ROUND_UP( + sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length(), 8) + - (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length()); + this->length_ = sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_flow_stats_request *fs = + (struct of13::ofp_flow_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + fs->table_id = this->table_id_; + memset(fs->pad, 0x0, 3); + fs->out_port = hton32(this->out_port_); + fs->out_group = hton32(this->out_group_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->cookie_mask = hton64(this->cookie_mask_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error MultipartRequestFlow::unpack(uint8_t *buffer) { + struct of13::ofp_flow_stats_request *fs = + (struct of13::ofp_flow_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = ntoh32(fs->out_port); + this->out_group_ = ntoh32(fs->out_group); + this->cookie_ = ntoh64(fs->cookie); + this->cookie_mask_ = ntoh64(fs->cookie_mask); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_flow_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +MultipartReplyFlow::MultipartReplyFlow() + : MultipartReply(OFPMP_FLOW) { +} + +MultipartReplyFlow::MultipartReplyFlow(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_FLOW, flags) { +} + +MultipartReplyFlow::MultipartReplyFlow(uint32_t xid, uint16_t flags, + std::vector flow_stats) + : MultipartReply(xid, of13::OFPMP_FLOW, flags), + flow_stats_(flow_stats) { + size_t stats_len = 0; + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + stats_len += it->length(); + } + this->length_ += stats_len; +} + +bool MultipartReplyFlow::operator==(const MultipartReplyFlow &other) const { + return ((MultipartReply::operator==(other)) + && (this->flow_stats_ == other.flow_stats_)); +} + +bool MultipartReplyFlow::operator!=(const MultipartReplyFlow &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyFlow::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->flow_stats_.begin(); + it != this->flow_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyFlow::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + of13::FlowStats stat; + stat.unpack(p); + this->flow_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void MultipartReplyFlow::flow_stats(std::vector flow_stats) { + this->flow_stats_ = flow_stats; + this->length_ += this->flow_stats_.size() + * sizeof(struct of13::ofp_flow_stats); +} + +void MultipartReplyFlow::add_flow_stats(of13::FlowStats stats) { + this->flow_stats_.push_back(stats); + this->length_ += stats.length(); +} + +MultipartRequestAggregate::MultipartRequestAggregate() + : MultipartRequest(OFPMP_AGGREGATE) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestAggregate::MultipartRequestAggregate(uint32_t xid, + uint16_t flags, uint8_t table_id, uint32_t out_port, uint32_t out_group, + uint64_t cookie, uint64_t cookie_mask) + : MultipartRequest(xid, of13::OFPMP_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match); +} + +MultipartRequestAggregate::MultipartRequestAggregate(uint32_t xid, + uint16_t flags, uint8_t table_id, uint32_t out_port, uint32_t out_group, + uint64_t cookie, uint64_t cookie_mask, of13::Match match) + : MultipartRequest(xid, of13::OFPMP_AGGREGATE, flags), + table_id_(table_id), + out_port_(out_port), + out_group_(out_group), + cookie_(cookie), + cookie_mask_(cookie_mask), + match_(match) { + this->length_ = length(); +} + +bool MultipartRequestAggregate::operator==( + const MultipartRequestAggregate &other) const { + return ((MultipartRequest::operator==(other)) + && (this->table_id_ == other.table_id_) + && (this->out_port_ == other.out_port_) + && (this->out_group_ == other.out_group_) + && (this->cookie_ == other.cookie_) + && (this->cookie_mask_ == other.cookie_mask_) + && (this->match_ == other.match_)); +} + +bool MultipartRequestAggregate::operator!=( + const MultipartRequestAggregate &other) const { + return !(*this == other); +} + +uint16_t MultipartRequestAggregate::length() { + return sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match) + ROUND_UP(this->match_.length(), 8); +} + +void MultipartRequestAggregate::match(of13::Match match) { + this->match_ = match; + this->length_ += ROUND_UP(match_.length(), 8); +} + +void MultipartRequestAggregate::add_oxm_field(OXMTLV &field) { + this->match_.add_oxm_field(field); +} + +void MultipartRequestAggregate::add_oxm_field(OXMTLV* field) { + this->match_.add_oxm_field(field); +} + +uint8_t* MultipartRequestAggregate::pack() { + size_t padding = length() + - (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match) + this->match_.length()); + this->length_ = length(); + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_aggregate_stats_request *fs = + (struct of13::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + fs->table_id = this->table_id_; + memset(fs->pad, 0x0, 3); + fs->out_port = hton32(this->out_port_); + fs->out_group = hton32(this->out_group_); + memset(fs->pad2, 0x0, 4); + fs->cookie = hton64(this->cookie_); + fs->cookie_mask = hton64(this->cookie_mask_); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.pack(p); + p += this->match_.length(); + memset(p, 0x0, padding); + return buffer; +} + +of_error MultipartRequestAggregate::unpack(uint8_t *buffer) { + struct of13::ofp_aggregate_stats_request *fs = + (struct of13::ofp_aggregate_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->table_id_ = fs->table_id; + this->out_port_ = ntoh32(fs->out_port); + this->out_group_ = ntoh32(fs->out_group); + this->cookie_ = ntoh64(fs->cookie); + this->cookie_mask_ = ntoh64(fs->cookie_mask); + uint8_t *p = buffer + + (sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_aggregate_stats_request) + - sizeof(struct of13::ofp_match)); + this->match_.unpack(p); + return 0; +} + +MultipartReplyAggregate::MultipartReplyAggregate() + : MultipartReply(OFPMP_AGGREGATE) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_reply); +} + +MultipartReplyAggregate::MultipartReplyAggregate(uint32_t xid, uint16_t flags, + uint64_t packet_count, uint64_t byte_count, uint32_t flow_count) + : MultipartReply(xid, of13::OFPMP_AGGREGATE, flags), + packet_count_(packet_count), + byte_count_(byte_count), + flow_count_(flow_count) { + this->length_ += sizeof(struct of13::ofp_aggregate_stats_reply); +} + +bool MultipartReplyAggregate::operator==( + const MultipartReplyAggregate &other) const { + return ((MultipartReply::operator==(other)) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_) + && (this->flow_count_ == other.flow_count_)); +} + +bool MultipartReplyAggregate::operator!=( + const MultipartReplyAggregate &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyAggregate::pack() { + uint8_t* buffer = MultipartReply::pack(); + struct of13::ofp_aggregate_stats_reply *ar = + (struct of13::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + ar->packet_count = hton64(this->packet_count_); + ar->byte_count = hton64(this->byte_count_); + ar->flow_count = hton32(this->flow_count_); + return buffer; +} + +of_error MultipartReplyAggregate::unpack(uint8_t *buffer) { + struct of13::ofp_aggregate_stats_reply *ar = + (struct of13::ofp_aggregate_stats_reply*) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartReply::unpack(buffer); + this->packet_count_ = ntoh64(ar->packet_count); + this->byte_count_ = ntoh64(ar->byte_count); + this->flow_count_ = ntoh32(ar->flow_count); + return 0; +} + +MultipartRequestTable::MultipartRequestTable() + : MultipartRequest(OFPMP_TABLE) { +} + +MultipartRequestTable::MultipartRequestTable(uint32_t xid, uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_TABLE, flags) { +} + +uint8_t* MultipartRequestTable::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestTable::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyTable::MultipartReplyTable() + : MultipartReply(OFPMP_TABLE) { +} + +MultipartReplyTable::MultipartReplyTable(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_TABLE, flags) { +} + +MultipartReplyTable::MultipartReplyTable(uint32_t xid, uint16_t flags, + std::vector table_stats) + : MultipartReply(xid, of13::OFPMP_TABLE, flags), + table_stats_(table_stats) { + this->length_ += table_stats.size() * sizeof(struct of13::ofp_table_stats); + +} + +bool MultipartReplyTable::operator==(const MultipartReplyTable &other) const { + return ((MultipartReply::operator==(other)) + && (this->table_stats_ == other.table_stats_)); +} + +bool MultipartReplyTable::operator!=(const MultipartReplyTable &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyTable::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->table_stats_.begin(); it != this->table_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_table_stats); + } + return buffer; +} + +of_error MultipartReplyTable::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_request); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_request); + while (len > 0) { + TableStats stat; + stat.unpack(p); + this->table_stats_.push_back(stat); + p += sizeof(struct of13::ofp_table_stats); + len -= sizeof(struct of13::ofp_table_stats); + } + return 0; +} + +void MultipartReplyTable::table_stats( + std::vector table_stats) { + this->table_stats_ = table_stats; + this->length_ += table_stats.size() * sizeof(struct of13::ofp_table_stats); +} + +void MultipartReplyTable::add_table_stat(of13::TableStats stat) { + this->table_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_table_stats); +} + +MultipartRequestPortStats::MultipartRequestPortStats() + : MultipartRequest(OFPMP_PORT_STATS) { + this->length_ += sizeof(struct of13::ofp_port_stats_request); +} + +MultipartRequestPortStats::MultipartRequestPortStats(uint32_t xid, + uint16_t flags, uint32_t port_no) + : MultipartRequest(xid, of13::OFPMP_PORT_STATS, flags), + port_no_(port_no) { + this->length_ += sizeof(struct of13::ofp_port_stats_request); + +} +; + +bool MultipartRequestPortStats::operator==( + const MultipartRequestPortStats &other) const { + return ((MultipartRequest::operator==(other)) + && (this->port_no_ == other.port_no_)); +} + +bool MultipartRequestPortStats::operator!=( + const MultipartRequestPortStats &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestPortStats::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_port_stats_request *ps = + (struct of13::ofp_port_stats_request *) (buffer + + sizeof(struct of13::ofp_multipart_request)); + ps->port_no = hton32(this->port_no_); + memset(ps->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestPortStats::unpack(uint8_t *buffer) { + struct of13::ofp_port_stats_request *ps = + (struct of13::ofp_port_stats_request *) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_port_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh32(ps->port_no); + return 0; +} + +MultipartReplyPortStats::MultipartReplyPortStats() + : MultipartReply(OFPMP_PORT_STATS) { +} + +MultipartReplyPortStats::MultipartReplyPortStats(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_PORT_STATS, flags) { +} + +MultipartReplyPortStats::MultipartReplyPortStats(uint32_t xid, uint16_t flags, + std::vector port_stats) + : MultipartReply(xid, of13::OFPMP_PORT_STATS, flags) { + this->port_stats_ = port_stats; + this->length_ = port_stats.size() * sizeof(struct of13::ofp_port_stats); + +} + +bool MultipartReplyPortStats::operator==( + const MultipartReplyPortStats &other) const { + return ((MultipartReply::operator==(other)) + && (this->port_stats_ == other.port_stats_)); +} + +bool MultipartReplyPortStats::operator!=( + const MultipartReplyPortStats &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyPortStats::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = this->port_stats_.begin(); + it != this->port_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_port_stats); + } + return buffer; +} + +of_error MultipartReplyPortStats::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_request); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_request); + while (len > 0) { + of13::PortStats stat; + stat.unpack(p); + this->port_stats_.push_back(stat); + p += sizeof(struct of13::ofp_port_stats); + len -= sizeof(struct of13::ofp_port_stats); + } + return 0; +} + +void MultipartReplyPortStats::port_stats( + std::vector port_stats) { + this->port_stats_ = port_stats; + this->length_ += port_stats.size() * sizeof(struct of13::ofp_port_stats); +} + +void MultipartReplyPortStats::add_port_stat(of13::PortStats stat) { + this->port_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_port_stats); +} + +MultipartRequestQueue::MultipartRequestQueue() + : MultipartRequest(OFPMP_QUEUE) { + this->length_ += sizeof(struct of13::ofp_queue_stats_request); +} + +MultipartRequestQueue::MultipartRequestQueue(uint32_t xid, uint16_t flags, + uint32_t port_no, uint32_t queue_id) + : MultipartRequest(xid, of13::OFPMP_QUEUE, flags), + port_no_(port_no), + queue_id_(queue_id) { + this->length_ += sizeof(struct of13::ofp_queue_stats_request); +} + +bool MultipartRequestQueue::operator==( + const MultipartRequestQueue &other) const { + return ((MultipartRequest::operator==(other)) + && (this->queue_id_ == other.queue_id_) + && (this->port_no_ == other.port_no_)); +} + +bool MultipartRequestQueue::operator!=( + const MultipartRequestQueue &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestQueue::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_queue_stats_request* qs = + (of13::ofp_queue_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + qs->port_no = hton32(this->port_no_); + qs->queue_id = hton32(this->queue_id_); + return buffer; +} + +of_error MultipartRequestQueue::unpack(uint8_t *buffer) { + struct of13::ofp_queue_stats_request* qs = + (of13::ofp_queue_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_queue_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_no_ = ntoh32(qs->port_no); + this->queue_id_ = ntoh32(qs->queue_id); + return 0; +} + +MultipartReplyQueue::MultipartReplyQueue() + : MultipartReply(OFPMP_QUEUE) { +} + +MultipartReplyQueue::MultipartReplyQueue(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_QUEUE, flags) { +} + +MultipartReplyQueue::MultipartReplyQueue(uint32_t xid, uint16_t flags, + std::vector queue_stats) + : MultipartReply(xid, of13::OFPMP_QUEUE, flags), + queue_stats_(queue_stats) { + this->length_ += queue_stats.size() * sizeof(struct of13::ofp_queue_stats); +} + +bool MultipartReplyQueue::operator==(const MultipartReplyQueue &other) const { + return ((MultipartReply::operator==(other)) + && (this->queue_stats_ == other.queue_stats_)); +} + +bool MultipartReplyQueue::operator!=(const MultipartReplyQueue &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyQueue::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->queue_stats_.begin(); it != this->queue_stats_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_queue_stats); + } + return buffer; +} + +of_error MultipartReplyQueue::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::QueueStats stat; + stat.unpack(p); + this->queue_stats_.push_back(stat); + p += sizeof(struct of13::ofp_queue_stats); + len -= sizeof(struct of13::ofp_queue_stats); + } + return 0; +} + +void MultipartReplyQueue::queue_stats( + std::vector queue_stats) { + this->queue_stats_ = queue_stats; + this->length_ += queue_stats.size() * sizeof(struct of13::ofp_queue_stats); +} + +void MultipartReplyQueue::add_queue_stat(of13::QueueStats stat) { + this->queue_stats_.push_back(stat); + this->length_ += sizeof(struct of13::ofp_queue_stats); +} + +MultipartRequestGroup::MultipartRequestGroup() + : MultipartRequest(OFPMP_GROUP) { + this->length_ += sizeof(struct of13::ofp_group_stats_request); +} + +MultipartRequestGroup::MultipartRequestGroup(uint32_t xid, uint16_t flags, + uint32_t group_id) + : MultipartRequest(xid, of13::OFPMP_GROUP, flags), + group_id_(group_id) { + this->length_ += sizeof(struct of13::ofp_group_stats_request); +} + +bool MultipartRequestGroup::operator==( + const MultipartRequestGroup &other) const { + return ((MultipartRequest::operator==(other)) + && (this->group_id_ == other.group_id_)); +} + +bool MultipartRequestGroup::operator!=( + const MultipartRequestGroup &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestGroup::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_group_stats_request* gs = + (of13::ofp_group_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + gs->group_id = hton32(this->group_id_); + memset(gs->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestGroup::unpack(uint8_t *buffer) { + struct of13::ofp_group_stats_request* gs = + (of13::ofp_group_stats_request*) (buffer + + sizeof(struct of13::ofp_multipart_request)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_group_stats_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->group_id_ = ntoh32(gs->group_id); + return 0; +} + +MultipartReplyGroup::MultipartReplyGroup() + : MultipartReply(OFPMP_GROUP) { +} + +MultipartReplyGroup::MultipartReplyGroup(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_GROUP, flags) { +} + +MultipartReplyGroup::MultipartReplyGroup(uint32_t xid, uint16_t flags, + std::vector group_stats) + : MultipartReply(xid, of13::OFPMP_GROUP, flags), + group_stats_(group_stats) { + this->length_ += group_stats_len(); +} + +bool MultipartReplyGroup::operator==(const MultipartReplyGroup &other) const { + return ((MultipartReply::operator==(other)) + && (this->group_stats_ == other.group_stats_)); +} + +bool MultipartReplyGroup::operator!=(const MultipartReplyGroup &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroup::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->group_stats_.begin(); it != this->group_stats_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyGroup::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::GroupStats stat; + stat.unpack(p); + this->group_stats_.push_back(stat); + p += stat.length(); + len -= stat.length(); + } + return 0; +} + +void MultipartReplyGroup::group_stats( + std::vector group_stats) { + this->group_stats_ = group_stats; + this->length_ += group_stats_len(); +} + +void MultipartReplyGroup::add_group_stats(of13::GroupStats stat) { + this->group_stats_.push_back(stat); + this->length_ += stat.length(); +} + +size_t MultipartReplyGroup::group_stats_len() { + size_t len; + for (std::vector::iterator it = + this->group_stats_.begin(); it != this->group_stats_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestGroupDesc::MultipartRequestGroupDesc() + : MultipartRequest(OFPMP_GROUP_DESC) { +} + +MultipartRequestGroupDesc::MultipartRequestGroupDesc(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_GROUP_DESC, flags) { +} + +uint8_t* MultipartRequestGroupDesc::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestGroupDesc::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc() + : MultipartReply(OFPMP_GROUP_DESC) { +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_GROUP_DESC, flags) { +} + +MultipartReplyGroupDesc::MultipartReplyGroupDesc(uint32_t xid, uint16_t flags, + std::vector group_desc) + : MultipartReply(xid, of13::OFPMP_GROUP_DESC, flags), + group_desc_(group_desc) { + this->length_ += desc_len(); +} + +bool MultipartReplyGroupDesc::operator==( + const MultipartReplyGroupDesc &other) const { + return ((MultipartReply::operator==(other)) + && (this->group_desc_ == other.group_desc_)); +} + +bool MultipartReplyGroupDesc::operator!=( + const MultipartReplyGroupDesc &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroupDesc::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->group_desc_.begin(); + it != this->group_desc_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyGroupDesc::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::GroupDesc desc; + desc.unpack(p); + this->group_desc_.push_back(desc); + p += desc.length(); + len -= desc.length(); + } + return 0; +} + +void MultipartReplyGroupDesc::group_desc( + std::vector group_desc) { + this->group_desc_ = group_desc; + this->length_ += desc_len(); +} + +void MultipartReplyGroupDesc::add_group_desc(of13::GroupDesc desc) { + this->group_desc_.push_back(desc); + this->length_ += desc.length(); +} + +size_t MultipartReplyGroupDesc::desc_len() { + size_t len = 0; + for (std::vector::iterator it = this->group_desc_.begin(); + it != this->group_desc_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestGroupFeatures::MultipartRequestGroupFeatures() + : MultipartRequest(OFPMP_GROUP_FEATURES) { +} + +MultipartRequestGroupFeatures::MultipartRequestGroupFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_GROUP_FEATURES, flags) { +} + +uint8_t* MultipartRequestGroupFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestGroupFeatures::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyGroupFeatures::MultipartReplyGroupFeatures() + : MultipartReply(OFPMP_GROUP_FEATURES) { +} + +MultipartReplyGroupFeatures::MultipartReplyGroupFeatures(uint32_t xid, + uint16_t flags, of13::GroupFeatures features) + : MultipartReply(xid, of13::OFPMP_GROUP_FEATURES, flags), + features_(features) { + this->features_ = features; + this->length_ += sizeof(struct of13::ofp_group_features); +} + +bool MultipartReplyGroupFeatures::operator==( + const MultipartReplyGroupFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->features_ == other.features_)); +} + +bool MultipartReplyGroupFeatures::operator!=( + const MultipartReplyGroupFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyGroupFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->features_.pack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyGroupFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->features_.unpack(buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestMeter::MultipartRequestMeter() + : MultipartRequest(OFPMP_METER) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +MultipartRequestMeter::MultipartRequestMeter(uint32_t xid, uint16_t flags, + uint32_t meter_id) + : MultipartRequest(xid, of13::OFPMP_METER, flags), + meter_id_(meter_id) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +bool MultipartRequestMeter::operator==( + const MultipartRequestMeter &other) const { + return ((MultipartRequest::operator==(other)) + && (this->meter_id_ == other.meter_id_)); +} + +bool MultipartRequestMeter::operator!=( + const MultipartRequestMeter &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestMeter::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + mr->meter_id = hton32(this->meter_id_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestMeter::unpack(uint8_t *buffer) { + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_meter_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->meter_id_ = ntoh32(mr->meter_id); + return 0; +} + +MultipartReplyMeter::MultipartReplyMeter() + : MultipartReply(OFPMP_METER) { +} + +MultipartReplyMeter::MultipartReplyMeter(uint32_t xid, uint16_t flags) + : MultipartReply(xid, of13::OFPMP_METER, flags) { +} + +MultipartReplyMeter::MultipartReplyMeter(uint32_t xid, uint16_t flags, + std::vector meter_stats) + : MultipartReply(xid, of13::OFPMP_METER, flags), + meter_stats_(meter_stats) { + this->length_ += meter_stats_len(); +} + +bool MultipartReplyMeter::operator==(const MultipartReplyMeter &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_stats_ == other.meter_stats_)); +} + +bool MultipartReplyMeter::operator!=(const MultipartReplyMeter &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeter::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = + this->meter_stats_.begin(); it != this->meter_stats_.end(); ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error MultipartReplyMeter::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + int32_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len > 0) { + of13::MeterStats stat; + stat.unpack(p); + this->meter_stats_.push_back(stat); + p += stat.len(); + len -= stat.len(); + } + return 0; +} + +void MultipartReplyMeter::meter_stats( + std::vector meter_stats) { + this->meter_stats_ = meter_stats; + this->length_ += meter_stats_len(); +} + +void MultipartReplyMeter::add_meter_stats(of13::MeterStats stat) { + this->meter_stats_.push_back(stat); + this->length_ += stat.len(); +} + +size_t MultipartReplyMeter::meter_stats_len() { + size_t len; + for (std::vector::iterator it = + this->meter_stats_.begin(); it != this->meter_stats_.end(); ++it) { + len += it->len(); + } + return len; +} + +MultipartRequestMeterConfig::MultipartRequestMeterConfig() + : MultipartRequest(OFPMP_METER_CONFIG) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +MultipartRequestMeterConfig::MultipartRequestMeterConfig(uint32_t xid, + uint16_t flags, uint32_t meter_id) + : MultipartRequest(xid, of13::OFPMP_METER, flags), + meter_id_(meter_id) { + this->length_ += sizeof(struct of13::ofp_meter_multipart_request); +} + +bool MultipartRequestMeterConfig::operator==( + const MultipartRequestMeterConfig &other) const { + return ((MultipartRequest::operator==(other)) + && (this->meter_id_ == other.meter_id_)); +} + +bool MultipartRequestMeterConfig::operator!=( + const MultipartRequestMeterConfig &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestMeterConfig::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + mr->meter_id = hton32(this->meter_id_); + memset(mr->pad, 0x0, 4); + return buffer; +} + +of_error MultipartRequestMeterConfig::unpack(uint8_t *buffer) { + struct of13::ofp_meter_multipart_request *mr = + (struct of13::ofp_meter_multipart_request *) (buffer + + sizeof(struct of13::ofp_multipart_reply)); + MultipartRequest::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_meter_multipart_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->meter_id_ = ntoh32(mr->meter_id); + return 0; +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig() + : MultipartReply(OFPMP_METER_CONFIG) { +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_METER_CONFIG, flags) { +} + +MultipartReplyMeterConfig::MultipartReplyMeterConfig(uint32_t xid, + uint16_t flags, std::vector meter_config) + : MultipartReply(xid, of13::OFPMP_METER_CONFIG, flags), + meter_config_(meter_config) { + this->length_ += meter_config_len(); +} + +bool MultipartReplyMeterConfig::operator==( + const MultipartReplyMeterConfig &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_config_ == other.meter_config_)); +} + +bool MultipartReplyMeterConfig::operator!=( + const MultipartReplyMeterConfig &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeterConfig::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->meter_config_.begin(); + it != this->meter_config_.end(); ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyMeterConfig::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + MeterConfig conf; + conf.unpack(p); + this->meter_config_.push_back(conf); + p += conf.length(); + len -= conf.length(); + } + return 0; +} + +void MultipartReplyMeterConfig::meter_config( + std::vector meter_config) { + this->meter_config_ = meter_config; + this->length_ += meter_config_len(); +} + +void MultipartReplyMeterConfig::add_meter_config(MeterConfig config) { + this->meter_config_.push_back(config); + this->length_ += config.length(); +} + +size_t MultipartReplyMeterConfig::meter_config_len() { + size_t len; + for (std::vector::iterator it = this->meter_config_.begin(); + it != this->meter_config_.end(); ++it) { + len += it->length(); + } + return len; +} + +MultipartRequestMeterFeatures::MultipartRequestMeterFeatures() + : MultipartRequest(OFPMP_METER_FEATURES) { +} + +MultipartRequestMeterFeatures::MultipartRequestMeterFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_METER_FEATURES, flags) { +} + +uint8_t* MultipartRequestMeterFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestMeterFeatures::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyMeterFeatures::MultipartReplyMeterFeatures() + : MultipartReply(OFPMP_METER_FEATURES) { +} + +MultipartReplyMeterFeatures::MultipartReplyMeterFeatures(uint32_t xid, + uint16_t flags, MeterFeatures features) + : MultipartReply(xid, of13::OFPMP_METER_FEATURES, flags), + meter_features_(features) { + this->meter_features_ = features; + this->length_ += sizeof(struct of13::ofp_meter_features); +} + +bool MultipartReplyMeterFeatures::operator==( + const MultipartReplyMeterFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->meter_features_ == other.meter_features_)); +} + +bool MultipartReplyMeterFeatures::operator!=( + const MultipartReplyMeterFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyMeterFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + this->meter_features_.pack( + buffer + sizeof(struct of13::ofp_multipart_reply)); + return buffer; +} + +of_error MultipartReplyMeterFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + this->meter_features_.unpack( + buffer + sizeof(struct of13::ofp_multipart_reply)); + return 0; +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures() + : MultipartRequest(OFPMP_TABLE_FEATURES) { +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_TABLE_FEATURES, flags) { +} + +MultipartRequestTableFeatures::MultipartRequestTableFeatures(uint32_t xid, + uint16_t flags, std::vector tables_features) + : MultipartRequest(xid, of13::OFPMP_TABLE_FEATURES, flags) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +bool MultipartRequestTableFeatures::operator==( + const MultipartRequestTableFeatures &other) const { + return ((MultipartRequest::operator==(other)) + && (this->tables_features_ == other.tables_features_)); +} + +bool MultipartRequestTableFeatures::operator!=( + const MultipartRequestTableFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestTableFeatures::pack() { + uint8_t* buffer = MultipartRequest::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartRequestTableFeatures::unpack(uint8_t *buffer) { + MultipartRequest::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + TableFeatures features; + features.unpack(p); + this->tables_features_.push_back(features); + p += features.length(); + len -= features.length(); + } + return 0; +} + +void MultipartRequestTableFeatures::tables_features( + std::vector tables_features) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +void MultipartRequestTableFeatures::add_table_features( + TableFeatures table_feature) { + this->tables_features_.push_back(table_feature); + this->length_ += table_feature.length(); +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures() + : MultipartReply(OFPMP_TABLE_FEATURES) { +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_TABLE_FEATURES, flags) { +} + +MultipartReplyTableFeatures::MultipartReplyTableFeatures(uint32_t xid, + uint16_t flags, std::vector tables_features) + : MultipartReply(xid, of13::OFPMP_TABLE_FEATURES, flags) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +bool MultipartReplyTableFeatures::operator==( + const MultipartReplyTableFeatures &other) const { + return ((MultipartReply::operator==(other)) + && (this->tables_features_ == other.tables_features_)); +} + +bool MultipartReplyTableFeatures::operator!=( + const MultipartReplyTableFeatures &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyTableFeatures::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct ofp_multipart_request); + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + it->pack(p); + p += it->length(); + } + return buffer; +} + +of_error MultipartReplyTableFeatures::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + while (len) { + TableFeatures features; + features.unpack(p); + this->tables_features_.push_back(features); + p += features.length(); + len -= features.length(); + } + return 0; +} + +void MultipartReplyTableFeatures::tables_features( + std::vector tables_features) { + this->tables_features_ = tables_features; + size_t features_len = 0; + for (std::vector::iterator it = + this->tables_features_.begin(); it != this->tables_features_.end(); + ++it) { + features_len += it->length(); + } + this->length_ += features_len; +} + +void MultipartReplyTableFeatures::add_table_features( + TableFeatures table_feature) { + this->tables_features_.push_back(table_feature); + this->length_ += table_feature.length(); +} + +MultipartRequestPortDescription::MultipartRequestPortDescription() + : MultipartRequest(OFPMP_PORT_DESC) { +} + +MultipartRequestPortDescription::MultipartRequestPortDescription(uint32_t xid, + uint16_t flags) + : MultipartRequest(xid, of13::OFPMP_PORT_DESC, flags) { +} + +uint8_t* MultipartRequestPortDescription::pack() { + uint8_t* buffer = MultipartRequest::pack(); + return buffer; +} + +of_error MultipartRequestPortDescription::unpack(uint8_t *buffer) { + return MultipartRequest::unpack(buffer); +} + +MultipartReplyPortDescription::MultipartReplyPortDescription() + : MultipartReply(OFPMP_PORT_DESC) { +} + +MultipartReplyPortDescription::MultipartReplyPortDescription(uint32_t xid, + uint16_t flags) + : MultipartReply(xid, of13::OFPMP_PORT_DESC, flags) { +} + +MultipartReplyPortDescription::MultipartReplyPortDescription(uint32_t xid, + uint16_t flags, std::vector ports) + : MultipartReply(xid, of13::OFPMP_PORT_DESC, flags) { + this->ports_ = ports; + this->length_ += ports.size() * sizeof(struct of13::ofp_port); +} + +bool MultipartReplyPortDescription::operator==( + const MultipartReplyPortDescription &other) const { + return ((MultipartReply::operator==(other)) + && (this->ports_ == other.ports_)); +} + +bool MultipartReplyPortDescription::operator!=( + const MultipartReplyPortDescription &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyPortDescription::pack() { + uint8_t* buffer = MultipartReply::pack(); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + for (std::vector::iterator it = this->ports_.begin(); + it != this->ports_.end(); ++it) { + it->pack(p); + p += sizeof(struct of13::ofp_port); + } + return buffer; +} + +of_error MultipartReplyPortDescription::unpack(uint8_t *buffer) { + MultipartReply::unpack(buffer); + uint8_t *p = buffer + sizeof(struct of13::ofp_multipart_reply); + size_t len = this->length_ - sizeof(struct of13::ofp_multipart_reply); + while (len) { + of13::Port port; + port.unpack(p); + this->ports_.push_back(port); + p += sizeof(struct of13::ofp_port); + len -= sizeof(struct of13::ofp_port); + } + return 0; +} + +void MultipartReplyPortDescription::ports(std::vector ports) { + this->ports_ = ports; + this->length_ += ports.size() * sizeof(struct of13::ofp_port); +} + +void MultipartReplyPortDescription::add_port(of13::Port port) { + this->ports_.push_back(port); + this->length_ += sizeof(struct of13::ofp_port); +} + +MultipartRequestExperimenter::MultipartRequestExperimenter() + : MultipartRequest(OFPMP_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +MultipartRequestExperimenter::MultipartRequestExperimenter(uint32_t xid, + uint16_t flags, uint32_t experimenter, uint32_t exp_type) + : MultipartRequest(xid, of13::OFPMP_EXPERIMENTER, flags), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +bool MultipartRequestExperimenter::operator==( + const MultipartRequestExperimenter &other) const { + return ((MultipartRequest::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool MultipartRequestExperimenter::operator!=( + const MultipartRequestExperimenter &other) const { + return !(*this == other); +} + +uint8_t* MultipartRequestExperimenter::pack() { + uint8_t* buffer = MultipartRequest::pack(); + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error MultipartRequestExperimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + MultipartRequest::unpack(buffer); + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +MultipartReplyExperimenter::MultipartReplyExperimenter() + : MultipartReply(OFPMP_EXPERIMENTER) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +MultipartReplyExperimenter::MultipartReplyExperimenter(uint32_t xid, + uint16_t flags, uint32_t experimenter, uint32_t exp_type) + : MultipartReply(xid, of13::OFPMP_EXPERIMENTER, flags), + experimenter_(experimenter), + exp_type_(exp_type) { + this->length_ += sizeof(struct of13::ofp_experimenter_multipart_header); +} + +bool MultipartReplyExperimenter::operator==( + const MultipartReplyExperimenter &other) const { + return ((MultipartReply::operator==(other)) + && (this->experimenter_ == other.experimenter_) + && (this->exp_type_ == other.exp_type_)); +} + +bool MultipartReplyExperimenter::operator!=( + const MultipartReplyExperimenter &other) const { + return !(*this == other); +} + +uint8_t* MultipartReplyExperimenter::pack() { + uint8_t* buffer = MultipartReply::pack(); + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + em->experimenter = hton32(this->experimenter_); + em->exp_type = hton32(this->exp_type_); + return buffer; +} + +of_error MultipartReplyExperimenter::unpack(uint8_t *buffer) { + struct of13::ofp_experimenter_multipart_header *em = + (struct of13::ofp_experimenter_multipart_header*) buffer; + MultipartReply::unpack(buffer); + if (this->length_ + < sizeof(struct of13::ofp_multipart_request) + + sizeof(struct of13::ofp_experimenter_multipart_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->experimenter_ = ntoh32(em->experimenter); + this->exp_type_ = ntoh32(em->exp_type); + return 0; +} + +QueueGetConfigRequest::QueueGetConfigRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REQUEST) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_request); +} + +QueueGetConfigRequest::QueueGetConfigRequest(uint32_t xid, uint32_t port) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REQUEST, xid), + port_(port) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_request); +} + +bool QueueGetConfigRequest::operator==( + const QueueGetConfigRequest &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_)); +} + +bool QueueGetConfigRequest::operator!=( + const QueueGetConfigRequest &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigRequest::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_queue_get_config_request * qc = + (struct of13::ofp_queue_get_config_request*) buffer; + qc->port = hton32(this->port_); + memset(qc->pad, 0x0, 4); + return buffer; +} + +of_error QueueGetConfigRequest::unpack(uint8_t *buffer) { + struct of13::ofp_queue_get_config_request * qc = + (struct of13::ofp_queue_get_config_request*) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct of13::ofp_queue_get_config_request)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->port_ = ntoh32(qc->port); + return 0; +} + +QueueGetConfigReply::QueueGetConfigReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint32_t port) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY, xid) { + this->port_ = port; + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply); +} + +QueueGetConfigReply::QueueGetConfigReply(uint32_t xid, uint16_t port, + std::list queues) + : OFMsg(of13::OFP_VERSION, of13::OFPT_QUEUE_GET_CONFIG_REPLY, xid), + port_(port), + queues_(queues) { + this->length_ = sizeof(struct of13::ofp_queue_get_config_reply) + + queues_len(); +} + +bool QueueGetConfigReply::operator==(const QueueGetConfigReply &other) const { + return ((OFMsg::operator==(other)) && (this->port_ == other.port_) + && (this->queues_ == other.queues_)); +} + +bool QueueGetConfigReply::operator!=(const QueueGetConfigReply &other) const { + return !(*this == other); +} + +uint8_t* QueueGetConfigReply::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_queue_get_config_reply *qr = + (struct of13::ofp_queue_get_config_reply *) buffer; + qr->port = hton32(this->port_); + memset(qr->pad, 0x0, 6); + uint8_t *p = buffer + sizeof(struct of13::ofp_queue_get_config_reply); + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + it->pack(p); + p += it->len(); + } + return buffer; +} + +of_error QueueGetConfigReply::unpack(uint8_t *buffer) { + struct of13::ofp_queue_get_config_reply *qr = + (struct of13::ofp_queue_get_config_reply *) buffer; + OFMsg::unpack(buffer); + this->port_ = ntoh32(qr->port); + uint8_t *p = buffer + sizeof(struct of13::ofp_queue_get_config_reply); + size_t len = this->length_ + - sizeof(struct of13::ofp_queue_get_config_reply); + while (len) { + PacketQueue pq; + pq.unpack(p); + this->queues_.push_back(pq); + p += pq.len(); + len -= pq.len(); + } + return 0; +} + +void QueueGetConfigReply::queues(std::list queues) { + this->queues_ = queues; + this->length_ += queues_len(); +} + +void QueueGetConfigReply::add_queue(PacketQueue queue) { + this->queues_.push_back(queue); + this->length_ += queue.len(); +} + +size_t QueueGetConfigReply::queues_len() { + size_t len; + for (std::list::iterator it = this->queues_.begin(), end = + this->queues_.end(); it != end; ++it) { + len += it->len(); + } + return len; +} + +BarrierRequest::BarrierRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REQUEST) { +} + +BarrierRequest::BarrierRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REQUEST, xid) { +} + +uint8_t* BarrierRequest::pack() { + return OFMsg::pack(); +} + +of_error BarrierRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +BarrierReply::BarrierReply() + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REPLY) { +} + +BarrierReply::BarrierReply(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_BARRIER_REPLY, xid) { +} + +uint8_t* BarrierReply::pack() { + return OFMsg::pack(); +} + +of_error BarrierReply::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + return 0; +} + +RoleRequest::RoleRequest() + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REQUEST) { +} + +RoleRequest::RoleRequest(uint32_t xid, uint32_t role, uint64_t generation_id) + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REQUEST, xid, role, + generation_id) { +} + +RoleReply::RoleReply() + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REPLY) { +} + +RoleReply::RoleReply(uint32_t xid, uint32_t role, uint64_t generation_id) + : RoleCommon(of13::OFP_VERSION, of13::OFPT_ROLE_REPLY, xid, role, + generation_id) { +} + +GetAsyncRequest::GetAsyncRequest() + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REQUEST) { +} + +GetAsyncRequest::GetAsyncRequest(uint32_t xid) + : OFMsg(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REQUEST, xid) { +} + +uint8_t* GetAsyncRequest::pack() { + return OFMsg::pack(); +} + +of_error GetAsyncRequest::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + if (this->length_ < sizeof(struct ofp_fluid_header)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + return 0; +} + +GetAsyncReply::GetAsyncReply() + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY) { +} + +GetAsyncReply::GetAsyncReply(uint32_t xid) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY, xid) { +} + +GetAsyncReply::GetAsyncReply(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_GET_ASYNC_REPLY, xid, + packet_in_mask, port_status_mask, flow_removed_mask) { + +} + +SetAsync::SetAsync() + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC) { +} + +SetAsync::SetAsync(uint32_t xid) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC, xid) { +} + +SetAsync::SetAsync(uint32_t xid, std::vector packet_in_mask, + std::vector port_status_mask, + std::vector flow_removed_mask) + : AsyncConfigCommon(of13::OFP_VERSION, of13::OFPT_SET_ASYNC, xid, + packet_in_mask, port_status_mask, flow_removed_mask) { + +} + +MeterMod::MeterMod() + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD) { + this->length_ = sizeof(struct of13::ofp_meter_mod); +} + +MeterMod::MeterMod(uint32_t xid, uint16_t command, uint16_t flags, + uint32_t meter_id) + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD, xid), + command_(command), + meter_id_(meter_id), + flags_(flags) { + this->length_ = sizeof(struct of13::ofp_meter_mod); +} + +MeterMod::MeterMod(uint32_t xid, uint16_t command, uint16_t flags, + uint32_t meter_id, MeterBandList bands) + : OFMsg(of13::OFP_VERSION, of13::OFPT_METER_MOD, xid), + command_(command), + meter_id_(meter_id), + flags_(flags), + bands_(bands) { + this->length_ = sizeof(struct of13::ofp_meter_mod) + bands.length(); +} + +bool MeterMod::operator==(const MeterMod &other) const { + return ((OFMsg::operator==(other)) && (this->command_ == other.command_) + && (this->flags_ == other.flags_) + && (this->meter_id_ == other.meter_id_) + && (this->bands_ == other.bands_)); +} + +bool MeterMod::operator!=(const MeterMod &other) const { + return !(*this == other); +} + +uint8_t* MeterMod::pack() { + uint8_t* buffer = OFMsg::pack(); + struct of13::ofp_meter_mod *mm = (struct of13::ofp_meter_mod *) buffer; + mm->command = hton16(this->command_); + mm->flags = hton16(this->flags_); + mm->meter_id = hton32(this->meter_id_); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_mod); + this->bands_.pack(p); + return buffer; +} + +of_error MeterMod::unpack(uint8_t *buffer) { + struct of13::ofp_meter_mod *mm = (struct of13::ofp_meter_mod *) buffer; + OFMsg::unpack(buffer); + if (this->length_ < sizeof(of13::ofp_meter_mod)) { + return openflow_error(of13::OFPET_BAD_REQUEST, of13::OFPBRC_BAD_LEN); + } + this->command_ = ntoh16(mm->command); + this->flags_ = ntoh16(mm->flags); + this->meter_id_ = ntoh32(mm->meter_id); + uint8_t *p = buffer + sizeof(struct of13::ofp_meter_mod); + this->bands_.length(this->length_ - sizeof(struct of13::ofp_meter_mod)); + this->bands_.unpack(p); + return 0; +} + +void MeterMod::bands(MeterBandList bands) { + this->bands_ = bands; + this->length_ += bands.length(); +} + +void MeterMod::add_band(MeterBand* band) { + this->bands_.add_band(band); + this->length_ += band->len(); +} + +} // End of namespace of13 +} //End of namespace fluid_msg + diff --git a/src/ovs/libfluid-msg/ofcommon/action.cc b/src/ovs/libfluid-msg/ofcommon/action.cc new file mode 100644 index 00000000..3d811c26 --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/action.cc @@ -0,0 +1,226 @@ +#include "libfluid-msg/ofcommon/action.hh" + +namespace fluid_msg { + +Action::Action() + : type_(0), + length_(0) { +} + +Action::Action(uint16_t type, uint16_t length) { + this->type_ = type; + this->length_ = length; +} + +bool Action::equals(const Action &other) { + return ((*this == other)); +} + +bool Action::operator==(const Action &other) const { + return ((this->type_ == other.type_) && (this->length_ == other.length_)); +} + +bool Action::operator!=(const Action &other) const { + return !(*this == other); +} + +size_t Action::pack(uint8_t *buffer) { + struct ofp_action_header *ac = (struct ofp_action_header *) buffer; + ac->type = hton16(this->type_); + ac->len = hton16(this->length_); + memset(ac->pad, 0x0, 4); + return 0; +} + +of_error Action::unpack(uint8_t *buffer) { + struct ofp_action_header *ac = (struct ofp_action_header *) buffer; + this->type_ = ntoh16(ac->type); + this->length_ = ntoh16(ac->len); + return 0; +} + +ActionList::ActionList(std::list action_list) { + this->action_list_ = action_list_; + for (std::list::const_iterator it = action_list.begin(); + it != action_list.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +ActionList::ActionList(const ActionList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = other.action_list_.begin(); + it != other.action_list_.end(); ++it) { + this->action_list_.push_back((*it)->clone()); + } +} + +ActionList::~ActionList() { + this->action_list_.remove_if(Action::delete_all); +} + +bool ActionList::operator==(const ActionList &other) const { + std::list::const_iterator ot = other.action_list_.begin(); + for (std::list::const_iterator it = this->action_list_.begin(); + it != this->action_list_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool ActionList::operator!=(const ActionList &other) const { + return !(*this == other); +} + +size_t ActionList::pack(uint8_t *buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->action_list_.begin(), end = + this->action_list_.end(); it != end; ++it) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +of_error ActionList::unpack10(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of10_action(type); + act->unpack(p); + this->action_list_.push_back(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +of_error ActionList::unpack13(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of13_action(type); + act->unpack(p); + this->action_list_.push_back(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +ActionList& ActionList::operator=(ActionList other) { + swap(*this, other); + return *this; +} + +void swap(ActionList& first, ActionList& second) { + std::swap(first.length_, second.length_); + first.action_list_.swap(second.action_list_); +} + +void ActionList::add_action(Action &act) { + Action *actn = act.clone(); + this->action_list_.push_back(actn); + this->length_ += act.length(); +} + +void ActionList::add_action(Action * act) { + this->action_list_.push_back(act); + this->length_ += act->length(); +} + +ActionSet::ActionSet(std::set action_set) { + this->action_set_ = action_set_; + for (std::set::const_iterator it = action_set.begin(); + it != action_set.end(); ++it) { + this->length_ += (*it)->length(); + } +} + +ActionSet::ActionSet(const ActionSet &other) { + this->length_ = other.length_; + for (std::set::const_iterator it = other.action_set_.begin(); + it != other.action_set_.end(); ++it) { + this->action_set_.insert((*it)->clone()); + } +} + +ActionSet::~ActionSet() { + for (std::set::const_iterator it = this->action_set_.begin(); + it != this->action_set_.end(); ++it) { + delete *it; + } +} + +bool ActionSet::operator==(const ActionSet &other) const { + std::set::const_iterator ot = other.action_set_.begin(); + for (std::set::const_iterator it = this->action_set_.begin(); + it != this->action_set_.end(); ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool ActionSet::operator!=(const ActionSet &other) const { + return !(*this == other); +} + +size_t ActionSet::pack(uint8_t *buffer) { + uint8_t *p = buffer; + for (std::set::iterator it = this->action_set_.begin(), end = + this->action_set_.end(); it != end; ++it) { + (*it)->pack(p); + p += (*it)->length(); + } + return 0; +} + +/*OpenFlow 1.0 doesn't have actions sets, so we do not + * need to implement two unpack versions like we did for + * the ActionList */ +of_error ActionSet::unpack(uint8_t *buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + Action *act; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + act = Action::make_of13_action(type); + act->unpack(p); + this->action_set_.insert(act); + len -= act->length(); + p += act->length(); + } + return 0; +} + +ActionSet& ActionSet::operator=(ActionSet other) { + swap(*this, other); + return *this; +} + +void swap(ActionSet& first, ActionSet& second) { + + std::swap(first.length_, second.length_); + std::swap(first.action_set_, second.action_set_); +} + +void ActionSet::add_action(Action &act) { + Action *actn = act.clone(); + this->action_set_.insert(actn); + this->length_ += act.length(); +} + +void ActionSet::add_action(Action *act) { + this->action_set_.insert(act); + this->length_ += act->length(); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/ofcommon/common.cc b/src/ovs/libfluid-msg/ofcommon/common.cc new file mode 100644 index 00000000..2a974d9e --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/common.cc @@ -0,0 +1,436 @@ +#include "libfluid-msg/ofcommon/common.hh" + +namespace fluid_msg { + +PortCommon::PortCommon() + : hw_addr_(), + name_(), + config_(0), + state_(0), + curr_(0), + advertised_(0), + supported_(0), + peer_(0) { +} + +PortCommon::PortCommon(EthAddress hw_addr, std::string name, uint32_t config, + uint32_t state, uint32_t curr, uint32_t advertised, uint32_t supported, + uint32_t peer) + : hw_addr_(hw_addr), + name_(name), + config_(config), + state_(state), + curr_(curr), + advertised_(advertised), + supported_(supported), + peer_(peer) { +} + +bool PortCommon::operator==(const PortCommon &other) const { + return ((this->hw_addr_ == other.hw_addr_) && (this->name_ == other.name_) + && (this->config_ == other.config_) && (this->state_ == other.state_) + && (this->curr_ == other.curr_) + && (this->advertised_ == other.advertised_) + && (this->supported_ == other.supported_) + && (this->peer_ == other.peer_)); +} + +bool PortCommon::operator!=(const PortCommon &other) const { + return !(*this == other); +} + +QueueProperty::QueueProperty() + : property_(0), + len_(0) { +} + +QueueProperty::QueueProperty(uint16_t property) + : property_(property), + len_(sizeof(struct ofp_queue_prop_header)) { +} + +bool QueueProperty::equals(const QueueProperty &other) { + return ((*this == other)); +} + +bool QueueProperty::operator==(const QueueProperty &other) const { + return ((this->property_ == other.property_) && (this->len_ == other.len_)); +} + +bool QueueProperty::operator!=(const QueueProperty &other) const { + return !(*this == other); +} + +size_t QueueProperty::pack(uint8_t* buffer) { + struct ofp_queue_prop_header *qp = (struct ofp_queue_prop_header*) buffer; + qp->property = hton16(this->property_); + qp->len = hton16(this->len_); + return this->len_; +} + +of_error QueueProperty::unpack(uint8_t* buffer) { + struct ofp_queue_prop_header *qp = (struct ofp_queue_prop_header*) buffer; + this->property_ = ntoh16(qp->property); + this->len_ = ntoh16(qp->len); + return 0; +} + +QueuePropertyList::QueuePropertyList(std::list property_list) { + this->property_list_ = property_list_; + for (std::list::const_iterator it = property_list.begin(); + it != property_list.end(); ++it) { + this->length_ += (*it)->len(); + } +} + +QueuePropertyList::QueuePropertyList(const QueuePropertyList &other) { + this->length_ = other.length_; + for (std::list::const_iterator it = + other.property_list_.begin(); it != other.property_list_.end(); ++it) { + this->property_list_.push_back((*it)->clone()); + } +} + +QueuePropertyList::~QueuePropertyList() { + this->property_list_.remove_if(QueueProperty::delete_all); +} + +bool QueuePropertyList::operator==(const QueuePropertyList &other) const { + std::list::const_iterator ot = other.property_list_.begin(); + for (std::list::const_iterator it = + this->property_list_.begin(); it != this->property_list_.end(); + ++it, ++ot) { + if (!((*it)->equals(**ot))) { + return false; + } + } + return true; +} + +bool QueuePropertyList::operator!=(const QueuePropertyList &other) const { + return !(*this == other); +} + +size_t QueuePropertyList::pack(uint8_t* buffer) { + uint8_t *p = buffer; + for (std::list::iterator it = this->property_list_.begin(), + end = this->property_list_.end(); it != end; it++) { + (*it)->pack(p); + p += (*it)->len(); + } + return 0; +} + +of_error QueuePropertyList::unpack10(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + QueueProperty *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = QueueProperty::make_queue_of10_property(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->len(); + p += prop->len(); + } + return 0; +} + +of_error QueuePropertyList::unpack13(uint8_t* buffer) { + uint8_t *p = buffer; + size_t len = this->length_; + QueueProperty *prop; + while (len) { + uint16_t type = ntoh16(*((uint16_t*) p)); + prop = QueueProperty::make_queue_of13_property(type); + prop->unpack(p); + this->property_list_.push_back(prop); + len -= prop->len(); + p += prop->len(); + } + return 0; +} + +QueuePropertyList& QueuePropertyList::operator=(QueuePropertyList other) { + swap(*this, other); + return *this; +} + +void swap(QueuePropertyList& first, QueuePropertyList& second) { + + std::swap(first.length_, second.length_); + std::swap(first.property_list_, second.property_list_); +} + +void QueuePropertyList::add_property(QueueProperty *prop) { + this->property_list_.push_back(prop); + this->length_ += prop->len(); +} + +QueuePropRate::QueuePropRate() + : QueueProperty(), + rate_(0) { +} + +QueuePropRate::QueuePropRate(uint16_t property) + : QueueProperty(property), + rate_(0) { +} +; + +QueuePropRate::QueuePropRate(uint16_t property, uint16_t rate) + : QueueProperty(property), + rate_(rate) { +} + +bool QueuePropRate::equals(const QueueProperty &other) { + if (const QueuePropRate * prop = dynamic_cast(&other)) { + return ((QueueProperty::equals(other)) && (this->rate_ == prop->rate_)); + } + else { + return false; + } +} + +PacketQueueCommon::PacketQueueCommon() + : len_(0), + queue_id_(0), + properties_() { +} + +PacketQueueCommon::PacketQueueCommon(uint32_t queue_id) + : len_(0), + queue_id_(queue_id) { +} + +void PacketQueueCommon::property(QueuePropertyList properties) { + this->properties_ = properties; + this->len_ += properties.length(); +} + +bool PacketQueueCommon::operator==(const PacketQueueCommon &other) const { + return ((this->properties_ == other.properties_) + && (this->len_ == other.len_)); +} + +bool PacketQueueCommon::operator!=(const PacketQueueCommon &other) const { + return !(*this == other); +} + +void PacketQueueCommon::add_property(QueueProperty* qp) { + this->properties_.add_property(qp); + this->len_ += qp->len(); +} + +SwitchDesc::SwitchDesc(std::string mfr_desc, std::string hw_desc, + std::string sw_desc, std::string serial_num, std::string dp_desc) { + this->mfr_desc_ = mfr_desc; + this->hw_desc_ = hw_desc; + this->sw_desc_ = sw_desc; + this->serial_num_ = serial_num; + this->dp_desc_ = dp_desc; +} + +bool SwitchDesc::operator==(const SwitchDesc &other) const { + return ((this->mfr_desc_ == other.mfr_desc_) + && (this->hw_desc_ == other.hw_desc_) + && (this->sw_desc_ == other.sw_desc_) + && (this->serial_num_ == other.serial_num_) + && (this->dp_desc_ == other.dp_desc_)); +} + +bool SwitchDesc::operator!=(const SwitchDesc &other) const { + return !(*this == other); +} + +size_t SwitchDesc::pack(uint8_t* buffer) { + struct ofp_desc *ds = (struct ofp_desc *) buffer; + memset(ds->mfr_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->hw_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->sw_desc, 0x0, DESC_FLUID_STR_LEN); + memset(ds->serial_num, 0x0, SERIAL_FLUID_NUM_LEN); + memset(ds->dp_desc, 0x0, DESC_FLUID_STR_LEN); + memcpy(ds->mfr_desc, this->mfr_desc_.c_str(), + this->mfr_desc_.size() < DESC_FLUID_STR_LEN ? + this->mfr_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->hw_desc, this->hw_desc_.c_str(), + this->hw_desc_.size() < DESC_FLUID_STR_LEN ? + this->hw_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->sw_desc, this->sw_desc_.c_str(), + this->sw_desc_.size() < DESC_FLUID_STR_LEN ? + this->sw_desc_.size() : DESC_FLUID_STR_LEN); + memcpy(ds->serial_num, this->serial_num_.c_str(), + this->serial_num_.size() < SERIAL_FLUID_NUM_LEN ? + this->serial_num_.size() : SERIAL_FLUID_NUM_LEN); + memcpy(ds->dp_desc, this->dp_desc_.c_str(), + this->dp_desc_.size() < DESC_FLUID_STR_LEN ? + this->dp_desc_.size() : DESC_FLUID_STR_LEN); + return 0; +} + +of_error SwitchDesc::unpack(uint8_t* buffer) { + struct ofp_desc *ds = (struct ofp_desc *) buffer; + this->mfr_desc_ = std::string(ds->mfr_desc); + this->hw_desc_ = std::string(ds->hw_desc); + this->sw_desc_ = std::string(ds->sw_desc); + this->serial_num_ = std::string(ds->serial_num); + this->dp_desc_ = std::string(ds->dp_desc); + + return 0; +} + +FlowStatsCommon::FlowStatsCommon() + : length_(0), + table_id_(0), + duration_sec_(0), + duration_nsec_(0), + priority_(0), + idle_timeout_(0), + hard_timeout_(0), + cookie_(0), + packet_count_(0), + byte_count_(0) { +} + +FlowStatsCommon::FlowStatsCommon(uint8_t table_id, uint32_t duration_sec, + uint32_t duration_nsec, uint16_t priority, uint16_t idle_timeout, + uint16_t hard_timeout, uint64_t cookie, uint64_t packet_count, + uint64_t byte_count) + : length_(0), + table_id_(table_id), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + priority_(priority), + idle_timeout_(idle_timeout), + hard_timeout_(hard_timeout), + cookie_(cookie), + packet_count_(packet_count), + byte_count_(byte_count) { +} + +bool FlowStatsCommon::operator==(const FlowStatsCommon &other) const { + return ((this->table_id_ == other.table_id_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->priority_ == other.priority_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->cookie_ == other.cookie_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool FlowStatsCommon::operator!=(const FlowStatsCommon &other) const { + return !(*this == other); +} + +TableStatsCommon::TableStatsCommon() + : table_id_(0), + active_count_(0), + lookup_count_(0), + matched_count_(0) { +} + +TableStatsCommon::TableStatsCommon(uint8_t table_id, uint32_t active_count, + uint64_t lookup_count, uint64_t matched_count) + : table_id_(table_id), + active_count_(active_count), + lookup_count_(lookup_count), + matched_count_(matched_count) { +} + +bool TableStatsCommon::operator==(const TableStatsCommon &other) const { + return ((this->table_id_ == other.table_id_) + && (this->active_count_ == other.active_count_) + && (this->lookup_count_ == other.lookup_count_) + && (this->matched_count_ == other.matched_count_)); +} + +bool TableStatsCommon::operator!=(const TableStatsCommon &other) const { + return !(*this == other); +} + +PortStatsCommon::PortStatsCommon() + : collisions_(0) { +} + +PortStatsCommon::PortStatsCommon(struct port_rx_tx_stats rx_tx_stats, + struct port_err_stats err_stats, uint64_t collisions) { + this->rx_tx_stats = rx_tx_stats; + this->err_stats = err_stats; + this->collisions_ = collisions; +} + +bool PortStatsCommon::operator==(const PortStatsCommon &other) const { + return ((this->rx_tx_stats == other.rx_tx_stats) + && (this->err_stats == other.err_stats) + && (this->collisions_ == other.collisions_)); +} + +bool PortStatsCommon::operator!=(const PortStatsCommon &other) const { + return !(*this == other); +} + +size_t PortStatsCommon::pack(uint8_t* buffer) { + struct port_rx_tx_stats *rt = (struct port_rx_tx_stats *) buffer; + struct port_err_stats *es = (struct port_err_stats *) (buffer + + sizeof(struct port_rx_tx_stats)); + rt->rx_packets = hton64(this->rx_tx_stats.rx_packets); + rt->tx_packets = hton64(this->rx_tx_stats.tx_packets); + rt->rx_bytes = hton64(this->rx_tx_stats.rx_bytes); + rt->tx_bytes = hton64(this->rx_tx_stats.tx_bytes); + rt->rx_dropped = hton64(this->rx_tx_stats.rx_dropped); + rt->tx_dropped = hton64(this->rx_tx_stats.tx_dropped); + es->rx_errors = hton64(this->err_stats.rx_errors); + es->tx_errors = hton64(this->err_stats.tx_errors); + es->rx_frame_err = hton64(this->err_stats.rx_frame_err); + es->rx_over_err = hton64(this->err_stats.rx_over_err); + es->rx_crc_err = hton64(this->err_stats.rx_crc_err); + return 0; +} + +of_error PortStatsCommon::unpack(uint8_t* buffer) { + struct port_rx_tx_stats *rt = (struct port_rx_tx_stats *) buffer; + struct port_err_stats *es = (struct port_err_stats *) (buffer + + sizeof(struct port_rx_tx_stats)); + this->rx_tx_stats.rx_packets = hton64(rt->rx_packets); + this->rx_tx_stats.tx_packets = hton64(rt->tx_packets); + this->rx_tx_stats.rx_bytes = hton64(rt->rx_bytes); + this->rx_tx_stats.tx_bytes = hton64(rt->tx_bytes); + this->rx_tx_stats.rx_dropped = hton64(rt->rx_dropped); + this->rx_tx_stats.tx_dropped = hton64(rt->tx_dropped); + this->err_stats.rx_errors = hton64(es->rx_errors); + this->err_stats.tx_errors = hton64(es->tx_errors); + this->err_stats.rx_frame_err = hton64(es->rx_frame_err); + this->err_stats.rx_over_err = hton64(es->rx_over_err); + this->err_stats.rx_crc_err = hton64(es->rx_crc_err); + return 0; +} + +QueueStatsCommon::QueueStatsCommon() + : queue_id_(0), + tx_bytes_(0), + tx_packets_(0), + tx_errors_(0) { +} + +QueueStatsCommon::QueueStatsCommon(uint32_t queue_id, uint64_t tx_bytes, + uint64_t tx_packets, uint64_t tx_errors) + : queue_id_(queue_id), + tx_bytes_(tx_bytes), + tx_packets_(tx_packets), + tx_errors_(tx_errors) { +} + +bool QueueStatsCommon::operator==(const QueueStatsCommon &other) const { + return ((this->queue_id_ == other.queue_id_) + && (this->tx_bytes_ == other.tx_bytes_) + && (this->tx_packets_ == other.tx_packets_) + && (this->tx_errors_ == other.tx_errors_)); +} + +bool QueueStatsCommon::operator!=(const QueueStatsCommon &other) const { + return !(*this == other); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/ofcommon/msg.cc b/src/ovs/libfluid-msg/ofcommon/msg.cc new file mode 100644 index 00000000..a8d51c50 --- /dev/null +++ b/src/ovs/libfluid-msg/ofcommon/msg.cc @@ -0,0 +1,479 @@ +#include "libfluid-msg/ofcommon/msg.hh" +#include "libfluid-msg/util/util.h" + +namespace fluid_msg { + +/*OpenFlow message header class constructor*/ +OFMsg::OFMsg(uint8_t version, uint8_t type) + : version_(version), + type_(type), + length_(sizeof(struct ofp_fluid_header)), + xid_(0) { +} + +/*OpenFlow message header class constructor*/ +OFMsg::OFMsg(uint8_t version, uint8_t type, uint32_t xid) + : version_(version), + type_(type), + length_(sizeof(struct ofp_fluid_header)), + xid_(xid) { +} + +uint8_t* OFMsg::pack() { + uint8_t * buffer = new uint8_t[this->length_]; + memset(buffer, 0x0, this->length_); + struct ofp_fluid_header *oh = (struct ofp_fluid_header*) buffer; + oh->version = this->version_; + oh->type = this->type_; + oh->length = hton16(this->length_); + oh->xid = hton32(this->xid_); + return buffer; +} + +of_error OFMsg::unpack(uint8_t *buffer) { + struct ofp_fluid_header *oh = (struct ofp_fluid_header*) buffer; + this->version_ = oh->version; + this->type_ = oh->type; + this->length_ = ntoh16(oh->length); + this->xid_ = ntoh32(oh->xid); + return 0; +} + +bool OFMsg::operator==(const OFMsg &other) const { + return ((this->version_ == other.version_) && (this->type_ == other.type_) + && (this->length_ == other.length_) && (this->xid_ == other.xid_)); +} + +bool OFMsg::operator!=(const OFMsg &other) const { + return !(*this == other); +} + +EchoCommon::EchoCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0) { +} +uint8_t* EchoCommon::pack() { + uint8_t *buffer = OFMsg::pack(); + memcpy(buffer + sizeof(struct ofp_fluid_header), this->data_, this->data_len_); + return buffer; +} + +of_error EchoCommon::unpack(uint8_t *buffer) { + OFMsg::unpack(buffer); + this->data_len_ = this->length_ - sizeof(struct ofp_fluid_header); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, buffer + sizeof(struct ofp_fluid_header), + this->data_len_); + } + else + this->data_ = NULL; + return 0; +} + +bool EchoCommon::operator==(const EchoCommon &other) const { + return ((OFMsg::operator==(other)) && (this->data_len_ == other.data_len_) + && (!memcmp(this->data_, other.data_, this->data_len_))); +} + +bool EchoCommon::operator!=(const EchoCommon &other) const { + return !(*this == other); +} + +void EchoCommon::data(void* data, size_t data_len) { + this->data_ = ::operator new(data_len); + memcpy(this->data_, data, data_len); + this->length_ += data_len; + this->data_len_ = data_len; +} + +EchoCommon::~EchoCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + err_type_(0), + code_(0) { +} +; + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t err_type, uint16_t code) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0) { + this->length_ = sizeof(struct ofp_fluid_error_msg); + this->err_type_ = err_type; + this->code_ = code; +} + +ErrorCommon::ErrorCommon(uint8_t version, uint8_t type, uint32_t xid, + uint16_t err_type, uint16_t code, void* data, size_t data_len) + : OFMsg(version, type, xid) { + this->length_ = sizeof(struct ofp_fluid_error_msg) + + (data_len <= 64 ? data_len : 64); + this->err_type_ = err_type; + this->code_ = code; + this->data_len_ = data_len; + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, data, this->data_len_); + } + else + this->data_ = NULL; +} + +ErrorCommon::~ErrorCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +bool ErrorCommon::operator==(const ErrorCommon &other) const { + return ((OFMsg::operator==(other)) && (this->err_type_ == other.err_type_) + && (this->code_ == other.code_) && (this->data_len_ == other.data_len_) + && (!memcmp(this->data_, other.data_, this->data_len_))); +} + +bool ErrorCommon::operator!=(const ErrorCommon &other) const { + return !(*this == other); +} + +void ErrorCommon::data(void *data, size_t data_len) { + this->data_ = ::operator new(data_len); + memcpy(this->data_, data, data_len); + this->data_len_ = data_len <= 64 ? data_len : 64; + this->length_ += this->data_len_; +} + +uint8_t* ErrorCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_fluid_error_msg *err = (struct ofp_fluid_error_msg*) buffer; + err->type = hton16(this->err_type_); + err->code = hton16(this->code_); + memcpy(err->data, this->data_, this->data_len_); + return buffer; +} + +of_error ErrorCommon::unpack(uint8_t *buffer) { + struct ofp_fluid_error_msg *err = (struct ofp_fluid_error_msg*) buffer; + OFMsg::unpack(buffer); + this->data_len_ = this->length_ - sizeof(struct ofp_fluid_error_msg); + this->err_type_ = ntoh16(err->type); + this->code_ = ntoh16(err->code); + if (this->data_len_) { + this->data_ = ::operator new(this->data_len_); + memcpy(this->data_, buffer + sizeof(struct ofp_fluid_error_msg), + this->data_len_); + } + else + this->data_ = NULL; + return 0; +} + +FeaturesReplyCommon::FeaturesReplyCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + datapath_id_(0), + n_buffers_(0), + n_tables_(0), + capabilities_(0) { +} + +FeaturesReplyCommon::FeaturesReplyCommon(uint8_t version, uint8_t type, + uint32_t xid, uint64_t datapath_id, uint32_t n_buffers, uint8_t n_tables, + uint32_t capabilities) + : OFMsg(version, type, xid), + datapath_id_(datapath_id), + n_buffers_(n_buffers), + n_tables_(n_tables), + capabilities_(capabilities) { +} + +bool FeaturesReplyCommon::operator==(const FeaturesReplyCommon &other) const { + return ((OFMsg::operator==(other)) + && (this->datapath_id_ == other.datapath_id_) + && (this->n_buffers_ == other.n_buffers_) + && (this->n_tables_ == other.n_tables_) + && (this->capabilities_ == other.capabilities_)); +} + +bool FeaturesReplyCommon::operator!=(const FeaturesReplyCommon &other) const { + return !(*this == other); +} + +SwitchConfigCommon::SwitchConfigCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + flags_(0x0), + miss_send_len_(0) { +} + +SwitchConfigCommon::SwitchConfigCommon(uint8_t version, uint8_t type, + uint32_t xid, uint16_t flags, uint16_t miss_send_len) + : OFMsg(version, type, xid), + flags_(flags), + miss_send_len_(miss_send_len) { + this->length_ = sizeof(struct ofp_fluid_switch_config); +} + +bool SwitchConfigCommon::operator==(const SwitchConfigCommon &other) const { + return ((OFMsg::operator==(other)) && (this->flags_ == other.flags_) + && (this->miss_send_len_ == other.miss_send_len_)); +} + +bool SwitchConfigCommon::operator!=(const SwitchConfigCommon &other) const { + return !(*this == other); +} + +uint8_t* SwitchConfigCommon::pack() { + uint8_t* buffer = OFMsg::pack(); + struct ofp_fluid_switch_config *conf = (struct ofp_fluid_switch_config*) buffer; + conf->flags = hton16(this->flags_); + conf->miss_send_len = hton16(this->miss_send_len_); + return buffer; +} + +of_error SwitchConfigCommon::unpack(uint8_t *buffer) { + struct ofp_fluid_switch_config *conf = (struct ofp_fluid_switch_config*) buffer; + OFMsg::unpack(buffer); + // if(this->length_ < sizeof(struct ofp_fluid_switch_config)){ + // return openflow_error(of10::OFPET_BAD_REQUEST, of10::OFPBRC_BAD_LEN); + // } + this->flags_ = ntoh16(conf->flags); + this->miss_send_len_ = ntoh16(conf->miss_send_len); + return 0; +} + +FlowModCommon::FlowModCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + cookie_(0), + idle_timeout_(0), + hard_timeout_(0), + priority_(0), + buffer_id_(0), + flags_(0) { +} + +FlowModCommon::FlowModCommon(uint8_t version, uint8_t type, uint32_t xid, + uint64_t cookie, uint16_t idle_timeout, + uint16_t hard_timeout, uint16_t priority, uint32_t buffer_id, + uint16_t flags) + : OFMsg(version, type, xid), + cookie_(cookie), + idle_timeout_(idle_timeout), + hard_timeout_(hard_timeout), + priority_(priority), + buffer_id_(buffer_id), + flags_(flags) { +} + +bool FlowModCommon::operator==(const FlowModCommon &other) const { + return ((OFMsg::operator==(other)) && (this->cookie_ == other.cookie_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->hard_timeout_ == other.hard_timeout_) + && (this->priority_ == other.priority_) + && (this->buffer_id_ == other.buffer_id_) + && (this->flags_ == other.flags_)); +} + +bool FlowModCommon::operator!=(const FlowModCommon &other) const { + return !(*this == other); +} + +PacketOutCommon::PacketOutCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + buffer_id_(0), + actions_len_(0) { +} + +PacketOutCommon::PacketOutCommon(uint8_t version, uint16_t type, uint32_t xid, + uint32_t buffer_id) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0), + buffer_id_(buffer_id), + actions_len_(0) { +} + +PacketOutCommon::~PacketOutCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +bool PacketOutCommon::operator==(const PacketOutCommon &other) const { + return ((OFMsg::operator==(other)) && (this->buffer_id_ == other.buffer_id_) + && (this->actions_len_ == other.actions_len_) + && (this->actions_ == other.actions_) + && (!memcmp(this->data_, other.data_, this->data_len_)) + && (this->data_len_ == other.data_len_)); +} + +bool PacketOutCommon::operator!=(const PacketOutCommon &other) const { + return !(*this == other); +} + +void PacketOutCommon::actions(ActionList actions) { + this->actions_ = actions; + this->actions_len_ = actions.length(); + this->length_ += actions_len(); +} + +void PacketOutCommon::add_action(Action &action) { + this->actions_.add_action(action); + this->length_ += action.length(); + this->actions_len_ += action.length(); +} + +void PacketOutCommon::add_action(Action *action) { + this->actions_.add_action(action); + this->length_ += action->length(); + this->actions_len_ += action->length(); +} + +void PacketOutCommon::data(void* data, size_t len) { + this->data_ = ::operator new(len); + memcpy(this->data_, data, len); + this->data_len_ = len; + this->length_ += len; +} + +PacketInCommon::PacketInCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + data_(NULL), + data_len_(0), + buffer_id_(0), + total_len_(0), + reason_(0) { +} + +PacketInCommon::PacketInCommon(uint8_t version, uint8_t type, uint32_t xid, + uint32_t buffer_id, uint16_t total_len, uint8_t reason) + : OFMsg(version, type, xid), + data_(NULL), + data_len_(0), + buffer_id_(buffer_id), + total_len_(total_len), + reason_(reason) { +} + +bool PacketInCommon::operator==(const PacketInCommon &other) const { + return ((OFMsg::operator==(other)) && (this->buffer_id_ == other.buffer_id_) + && (this->total_len_ == other.total_len_) + && (this->reason_ == other.reason_) + && (!memcmp(this->data_, other.data_, this->data_len_)) + && (this->data_len_ == other.data_len_)); +} + +bool PacketInCommon::operator!=(const PacketInCommon &other) const { + return !(*this == other); +} + +void PacketInCommon::data(void* data, size_t len) { + this->data_ = ::operator new(len); + memcpy(this->data_, data, len); + this->length_ += len; + this->data_len_ = len; +} + +PacketInCommon::~PacketInCommon() { + if (this->data_len_) { + ::operator delete(this->data_); + } +} + +FlowRemovedCommon::FlowRemovedCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + cookie_(0), + priority_(0), + reason_(0), + duration_sec_(0), + duration_nsec_(0), + idle_timeout_(0), + packet_count_(0), + byte_count_(0) { +} + +FlowRemovedCommon::FlowRemovedCommon(uint8_t version, uint8_t type, + uint32_t xid, uint64_t cookie, uint16_t priority, uint8_t reason, + uint32_t duration_sec, uint32_t duration_nsec, uint16_t idle_timeout, + uint64_t packet_count, uint64_t byte_count) + : OFMsg(version, type, xid), + cookie_(cookie), + priority_(priority), + reason_(reason), + duration_sec_(duration_sec), + duration_nsec_(duration_nsec), + idle_timeout_(idle_timeout), + packet_count_(packet_count), + byte_count_(byte_count) { +} + +bool FlowRemovedCommon::operator==(const FlowRemovedCommon &other) const { + return ((OFMsg::operator==(other)) && (this->cookie_ == other.cookie_) + && (this->priority_ == other.priority_) + && (this->reason_ == other.reason_) + && (this->duration_sec_ == other.duration_sec_) + && (this->duration_nsec_ == other.duration_nsec_) + && (this->idle_timeout_ == other.idle_timeout_) + && (this->packet_count_ == other.packet_count_) + && (this->byte_count_ == other.byte_count_)); +} + +bool FlowRemovedCommon::operator!=(const FlowRemovedCommon &other) const { + return !(*this == other); +} + +PortStatusCommon::PortStatusCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + reason_(0) { +} + +PortStatusCommon::PortStatusCommon(uint8_t version, uint8_t type, uint32_t xid, + uint8_t reason) + : OFMsg(version, type, xid), + reason_(reason) { +} + +bool PortStatusCommon::operator==(const PortStatusCommon &other) const { + return ((OFMsg::operator==(other)) && (this->reason_ == other.reason_)); +} + +bool PortStatusCommon::operator!=(const PortStatusCommon &other) const { + return !(*this == other); +} + +PortModCommon::PortModCommon(uint8_t version, uint8_t type) + : OFMsg(version, type), + config_(0), + mask_(0), + advertise_(0) { +} + +PortModCommon::PortModCommon(uint8_t version, uint8_t type, uint32_t xid, + EthAddress hw_addr, uint32_t config, uint32_t mask, uint32_t advertise) + : OFMsg(version, type, xid), + hw_addr_(hw_addr), + config_(config), + mask_(mask), + advertise_(advertise) { +} + +bool PortModCommon::operator==(const PortModCommon &other) const { + return ((OFMsg::operator==(other)) && (this->hw_addr_ == other.hw_addr_) + && (this->config_ == other.config_) && (this->mask_ == other.mask_) + && (this->advertise_ == other.advertise_)); +} + +bool PortModCommon::operator!=(const PortModCommon &other) const { + return !(*this == other); +} + +} //End of namespace fluid_msg diff --git a/src/ovs/libfluid-msg/util/ethaddr.cc b/src/ovs/libfluid-msg/util/ethaddr.cc new file mode 100644 index 00000000..fa5ee6e3 --- /dev/null +++ b/src/ovs/libfluid-msg/util/ethaddr.cc @@ -0,0 +1,65 @@ +#include "libfluid-msg/util/ethaddr.hh" +#include + +namespace fluid_msg{ + +EthAddress::EthAddress():data(){ +} + +EthAddress::EthAddress(const char* address) { + std::string sadress(address); + memcpy(this->data, data_from_string(address), IFHWADDRLEN); +} + +EthAddress::EthAddress(const std::string &address) { + memcpy(this->data, data_from_string(address),IFHWADDRLEN); +} + +EthAddress::EthAddress(const uint8_t* data) { + memcpy(this->data, data, IFHWADDRLEN); +} + +EthAddress::EthAddress(const EthAddress &other) { + memcpy(this->data, other.data, IFHWADDRLEN); +} + +EthAddress& EthAddress::operator=(const EthAddress &other) { + if (this != &other) { + memcpy(this->data, other.data, IFHWADDRLEN); + } + return *this; +} + +bool EthAddress::operator==(const EthAddress &other) const { + return memcmp(other.data, this->data, IFHWADDRLEN) == 0; +} + +std::string EthAddress::to_string() const { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (int i = 0; i < IFHWADDRLEN; i++) { + ss << std::setw(2) << (int) data[i]; + if (i < IFHWADDRLEN - 1) + ss << ':'; + } + + return ss.str(); +} +void EthAddress::set_data(uint8_t* array){ + memcpy(this->data, array, IFHWADDRLEN); +} + +uint8_t* EthAddress::data_from_string(const std::string &address) { + static uint8_t data[6]; + char sc; + int byte; + std::stringstream ss(address); + ss << std::hex; + for (int i = 0; i < IFHWADDRLEN; i++) { + ss >> byte; + ss >> sc; + data[i] = (uint8_t) byte; + } + return data; +} +} diff --git a/src/ovs/libfluid-msg/util/ipaddr.cc b/src/ovs/libfluid-msg/util/ipaddr.cc new file mode 100644 index 00000000..38cfa5d8 --- /dev/null +++ b/src/ovs/libfluid-msg/util/ipaddr.cc @@ -0,0 +1,130 @@ +#include "libfluid-msg/util/ipaddr.hh" +#include +#include + +namespace fluid_msg{ + +IPAddress::IPAddress():version(NONE){ + memset(&ipv6, 0x0, 16); +} + +IPAddress::IPAddress(const char* address){ + std::string saddress(address); + if (saddress.find('.') != std::string::npos){ + this->version = IPV4; + this->ipv4 = IPv4from_string(address); + } + else if (saddress.find(':') != std::string::npos){ + this->version = IPV6; + struct in6_addr addr = IPv6from_string(address); + memcpy(this->ipv6, &addr, 16); + } +} + +IPAddress::IPAddress(const std::string &address){ + if (address.find('.') != std::string::npos){ + this->version = IPV4; + this->ipv4 = IPv4from_string(address); + } + else if (address.find(':') != std::string::npos){ + this->version = IPV6; + struct in6_addr addr = IPv6from_string(address); + memcpy(this->ipv6, &addr, 16); + } +} + +IPAddress::IPAddress(const IPAddress &other): version(other.version) { + if(this->version == IPV4){ + this->ipv4 = other.ipv4; + } + else { + memcpy(&this->ipv6, &other.ipv6, 16); + } +} + +IPAddress::IPAddress(const uint32_t ip_addr): version(IPV4), ipv4(ip_addr){ +} + +IPAddress::IPAddress(const uint8_t ip_addr[16]):version(IPV6){ + memcpy(this->ipv6, ip_addr, 16); +} + +IPAddress::IPAddress(const struct in_addr& ip_addr):version(IPV4), ipv4(ip_addr.s_addr) { +} + +IPAddress::IPAddress(const struct in6_addr& ip_addr):version(IPV6){ + memcpy(&ipv6, &ip_addr, sizeof(struct in6_addr)); +} + +IPAddress& IPAddress::operator=(const IPAddress &other) { + if (this != &other) { + this->version = other.version; + if(this->version == IPV4){ + this->ipv4 = other.ipv4; + } + else { + memcpy(&this->ipv6, &other.ipv6, 16); + } + } + return *this; +} + +bool IPAddress::operator==(const IPAddress &other) const { + if (this->version == IPV4 && other.version == IPV4){ + return (this->ipv4 == other.ipv4); + } + else { + if (this->version == IPV6 && other.version == IPV6){ + return memcmp(other.ipv6, &other.ipv6, 16); + } + } + return false; + +} + +int IPAddress::get_version() const { + return this->version; +} + +void IPAddress::setIPv4(uint32_t address){ + this->version = IPV4; + this->ipv4 = address; +} + +void IPAddress::setIPv6(uint8_t address[16]){ + this->version = IPV6; + memcpy(this->ipv6, address, 16); +} + +uint32_t IPAddress::getIPv4(){ + return this->ipv4; +} + +uint8_t* IPAddress::getIPv6(){ + return this->ipv6; +} + +uint32_t IPAddress::IPv4from_string(const std::string &address){ + struct in_addr n; + int pos = address.find('/'); + if (pos != std::string::npos){ + int prefix = atoi(address.substr(pos+1).c_str()); + std::string ip = address.substr(0, pos); + inet_pton(AF_INET, ip.c_str(), &n); + for(int i = prefix; i < 32; i++){ + n.s_addr &= ~(1 << i); + } + } + else{ + inet_pton(AF_INET, address.c_str(), &n); + } + return n.s_addr; +} + +struct in6_addr IPAddress::IPv6from_string(const std::string &address){ + struct in6_addr n6; + inet_pton(AF_INET6, address.c_str(), &n6); + return n6; +} + +} diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp new file mode 100644 index 00000000..e7f9a079 --- /dev/null +++ b/src/ovs/of_controller.cpp @@ -0,0 +1,274 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#include + +#include "of_controller.h" +#include "aca_log.h" +#include "aca_util.h" +#include "aca_on_demand_engine.h" + +using namespace fluid_base; +using namespace fluid_msg; + +void OFController::stop() { + switch_map_mutex.lock(); + + for (auto iter: switch_conn_map) { + // close all OFConnection + if (NULL != iter.second) { + iter.second->close(); + } + } + switch_conn_map.clear(); + switch_id_map.clear(); + + switch_map_mutex.unlock(); +} + +void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* data, size_t len) { + if (type == fluid_msg::of13::OFPT_FEATURES_REPLY) { + ACA_LOG_INFO("OFController::message_callback - ovs connection id=%d up\n", ofconn->get_id()); + + fluid_msg::of13::FeaturesReply reply; + auto err = reply.unpack((uint8_t *) data); + if (err != 0) { + ACA_LOG_ERROR("%s", "OFController::message_callback - failed to parse feature reply\n"); + return; + } else { + uint64_t dpid = reply.datapath_id(); + ACA_LOG_INFO("OFController::message_callback - ovs connection %d with dpid %ld\n", ofconn->get_id(), dpid); + + // parse which bridge is the connection from + std::string bridge_name = switch_dpid_map[dpid]; + add_switch_to_conn_map(bridge_name, ofconn->get_id(), ofconn); + + // setup default flows for each bridge + if (bridge_name == "br-int") { + setup_default_br_int_flows(); + } + + if (bridge_name == "br-tun") { + setup_default_br_tun_flows(); + } + } + } else if (type == fluid_msg::of13::OFPT_BARRIER_REPLY) { + auto t = std::chrono::high_resolution_clock::now(); + ACA_LOG_INFO("OFController::message_callback - recv OFPT_BARRIER_REPLY on %ld\n", t.time_since_epoch().count()); + } else if (type == fluid_msg::of13::OFPT_PACKET_IN) { + fluid_msg::of13::PacketIn *pin = new of13::PacketIn(); + pin->unpack((uint8_t *) data); + uint32_t in_port = pin->match().in_port()->value(); + + // pass new allocated memory of packet-in to ACA_On_Demand_Engine to determine which type of request it is + aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().thread_pool_.push( + std::bind(&aca_on_demand_engine::ACA_On_Demand_Engine::parse_packet, + &aca_on_demand_engine::ACA_On_Demand_Engine::get_instance(), + in_port, (void *)pin->data())); + } else if (type == 33) { // OFPRAW_OFPT14_BUNDLE_CONTROL + auto t = std::chrono::high_resolution_clock::now(); + + BundleReplyMessage bundle_reply; + bundle_reply.unpack(data); + ACA_LOG_INFO("OFController::message_callback - recv bundle_ctrl_reply of type %ld of bundle id %ld on %ld\n", + bundle_reply.get_type(), + bundle_reply.get_bundle_id(), + t.time_since_epoch().count()); + } +} + +void OFController::connection_callback(OFConnection* ofconn, OFConnection::Event type) { + if (type == OFConnection::EVENT_STARTED) { + ACA_LOG_INFO("OFController::connection_callback - ovs connection id=%d started\n", ofconn->get_id()); + } else if (type == OFConnection::EVENT_ESTABLISHED) { + ACA_LOG_INFO("OFController::connection_callback - ovs connection ver=%d id=%d established\n", ofconn->get_version(), ofconn->get_id()); + } else if (type == OFConnection::EVENT_FAILED_NEGOTIATION) { + ACA_LOG_ERROR("OFController::connection_callback - ovs connection id=%d failed version negotiation\n", ofconn->get_id()); + } else if (type == OFConnection::EVENT_CLOSED) { + std::string bridge = switch_id_map[ofconn->get_id()]; + ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed by user, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); + remove_switch_from_conn_map(ofconn->get_id()); + remove_switch_from_conn_map(bridge); + } else if (type == OFConnection::EVENT_DEAD) { + std::string bridge = switch_id_map[ofconn->get_id()]; + ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed due to inactivity, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); + remove_switch_from_conn_map(ofconn->get_id()); + remove_switch_from_conn_map(bridge); + } +} + +OFConnection* OFController::get_instance(std::string bridge) { + OFConnection* ofconn = NULL; + + switch_map_mutex.lock(); + ofconn = switch_conn_map[bridge]; + switch_map_mutex.unlock(); + + if (NULL == ofconn) { + ACA_LOG_ERROR("OFController::get_instance - switch %s not found\n", bridge.c_str()); + } + + return ofconn; +} + +void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn) { + switch_map_mutex.lock(); + if (switch_conn_map.find(bridge) != switch_conn_map.end()) { + // if existing already, remove then insert to update + remove_switch_from_conn_map(bridge); + } + switch_conn_map[bridge] = ofconn; + + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { + // if existing already, remove then insert to update + remove_switch_from_conn_map(ofconn_id); + } + switch_id_map[ofconn_id] = bridge; + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::add_switch_to_conn_map - ovs connection id=%d bridge=%s added to switch map\n", + ofconn->get_id(), bridge.c_str()); +} + +void OFController::remove_switch_from_conn_map(std::string bridge) { + switch_map_mutex.lock(); + auto ofconn_iter = switch_conn_map.find(bridge); + + // if found, remove + if (ofconn_iter != switch_conn_map.end()) { + if (NULL != ofconn_iter->second) { // k is bridge name, v is OFConnection* + ofconn_iter->second->close(); + } + switch_conn_map.erase(bridge); + } + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection bridge=%s removed from switch map\n", + bridge.c_str()); +} + +void OFController::remove_switch_from_conn_map(int ofconn_id) { + switch_map_mutex.lock(); + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { + switch_id_map.erase(ofconn_id); + } + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection id=%d removed from switch map\n", + ofconn_id); +} + +void OFController::send_flow(OFConnection *ofconn, ofmsg_ptr_t &&p) { + p->set_xid(xid.fetch_add(1)); + auto buf = p->pack(); + + if (!buf) { + return; + } + + ofconn->send(buf->data(), buf->len()); +} + +void OFController::send_packet_out(OFConnection *ofconn, ofbuf_ptr_t &&po) { + if (!po) { + return; + } + + ofconn->send(po->data(), po->len()); +} + +void OFController::send_bundle_flow_mods(OFConnection *ofconn, std::vector flow_mods) { + xid.fetch_add(1); + BundleFlowModMessage bundle(flow_mods, &xid); + auto buf_open_req = bundle.pack_open_req(); + ofconn->send(buf_open_req->data(), buf_open_req->len()); + ACA_LOG_INFO("OFController::send_bundle_flow_mods - ovs connection id=%d send bundle open request of bundle_id %ld\n", + ofconn->get_id(), bundle.get_bundle_id()); + + // handle flow-mods + for (auto flow_mod : bundle.pack_flow_mods()) { + ofconn->send(flow_mod->data(), flow_mod->len()); + } + + auto buf_commit_req = bundle.pack_commit_req(); + ofconn->send(buf_commit_req->data(), buf_commit_req->len()); + ACA_LOG_INFO("OFController::send_bundle_flow_mods - ovs connection id=%d send bundle commit request of bundle_id %ld\n", + ofconn->get_id(), bundle.get_bundle_id()); +} + +void OFController::setup_default_br_int_flows() { + OFConnection* ofconn_br_int = get_instance("br-int"); + + if (NULL != ofconn_br_int) { + send_flow(ofconn_br_int, create_add_flow("table=0,priority=0, actions=NORMAL")); + } else { + ACA_LOG_ERROR("OFController::setup_default_br_int_flows - ovs connection not found\n"); + } + + ofconn_br_int = NULL; +} + +void OFController::setup_default_br_tun_flows() { + OFConnection* ofconn_br_tun = get_instance("br-tun"); + + if (NULL != ofconn_br_tun) { + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=0, actions=NORMAL")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=50,arp,arp_op=1, actions=CONTROLLER")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=1,in_port=" + port_id_map["patch-int"] + " actions=resubmit(,2)")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)")); + send_flow(ofconn_br_tun, create_add_flow("table=20,priority=1 actions=CONTROLLER")); + send_flow(ofconn_br_tun, create_add_flow("table=2,priority=25,icmp,icmp_type=8,in_port=" + port_id_map["patch-int"] + " actions=resubmit(,52)")); + send_flow(ofconn_br_tun, create_add_flow("table=52,priority=1 actions=resubmit(,20)")); + send_flow(ofconn_br_tun, create_add_flow("table=0,priority=25,in_port=" + port_id_map["vxlan-generic"] + " actions=resubmit(,4)")); + } else { + ACA_LOG_ERROR("OFController::setup_default_br_tun_flows - ovs connection not found\n"); + } + + ofconn_br_tun = NULL; +} + +void OFController::execute_flow(const std::string br, const std::string flow_str, const std::string action) { + OFConnection* ofconn_br = get_instance(br); + + if (NULL != ofconn_br) { + if (action == "add") { + send_flow(ofconn_br, create_add_flow(flow_str)); + } else if (action == "mod") { + // --strict mod + send_flow(ofconn_br, create_mod_flow(flow_str, true)); + } else if (action == "del") { + // --strict del + send_flow(ofconn_br, create_del_flow(flow_str, true)); + } else { + ACA_LOG_ERROR("OFController::execute_flow - action %s not supported in flow %s\n", action.c_str(), flow_str.c_str()); + } + } else { + ACA_LOG_ERROR("OFController::execute_flow - ovs connection to bridge %s not found\n", br.c_str()); + } + + ofconn_br = NULL; +} + +void OFController::packet_out(const char* br, const char* opt) { + OFConnection* ofconn_br = get_instance(std::string(br)); + + if (NULL != ofconn_br) { + send_packet_out(ofconn_br, create_packet_out(opt)); + } else { + ACA_LOG_ERROR("OFController::packet_out - ovs connection to bridge %s not found\n", br); + } + + ofconn_br = NULL; +} \ No newline at end of file diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp new file mode 100644 index 00000000..408b739f --- /dev/null +++ b/src/ovs/of_message.cpp @@ -0,0 +1,298 @@ +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#include "of_message.h" +#include "aca_log.h" +#include "aca_util.h" + +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP + +#include +#include +#include +#include +#include +#include + +enum { + ADD_FLOW = 0, + MODIFY_FLOW = 1, + MODIFY_FLOW_STRICT = 2, + DELETE_FLOW = 3, + DELETE_FLOW_STRICT = 4, +}; + +template +struct FreeDeleter { + void operator()(T* p) const { + free(p); + } +}; +typedef std::unique_ptr> OFString; +typedef std::unique_ptr> OFPact; + +const ofputil_protocol DEFAULT_OF_VERSION = OFPUTIL_P_OF13_OXM; +const ofputil_protocol BUNDLE_OF_VERSION = OFPUTIL_P_OF14_OXM; + +class OFPBuf : public OFRawBuf { +public: + OFPBuf(ofpbuf* b) : _buf(b) {} + ~OFPBuf() override { + ofpbuf_delete(_buf); + _buf = nullptr; + } + void* data() override { + return _buf->data; + } + size_t len() override { + return _buf->size; + } + +private: + struct ofpbuf* _buf; +}; + +class OFBaseMessage : public OFMessage { +public: + OFBaseMessage() : _xid(0) {} + uint32_t xid() override { + return _xid; + } + void set_xid(uint32_t id) override { + _xid = id; + } + + ofbuf_ptr_t pack_ofpbuf(struct ofpbuf* buf) { + auto header = static_cast(buf->data); + header->xid = htonl(_xid); + + ofpmsg_update_length(buf); + + return std::make_shared(buf); + } + virtual ~OFBaseMessage() = default; + +private: + uint32_t _xid; +}; + +class FlowModMessage : public OFBaseMessage { +public: + FlowModMessage(int op_type, const std::string& flow, bool bundle = false) : + _op_type(op_type), + _flow(flow) + { + if (bundle) { + _of_ver = BUNDLE_OF_VERSION; + } else { + _of_ver = DEFAULT_OF_VERSION; + } + } + + ~FlowModMessage() override = default; + + ofbuf_ptr_t pack() override { + int command = OFPFC_ADD; + std::string cmd_str = "ADD"; + + switch (_op_type) { + case MODIFY_FLOW: + command = OFPFC_MODIFY; + cmd_str = "MOD"; + break; + + case MODIFY_FLOW_STRICT: + command = OFPFC_MODIFY_STRICT; + cmd_str = "MOD STRICT"; + break; + + case DELETE_FLOW: + command = OFPFC_DELETE; + cmd_str = "DELETE"; + break; + + case DELETE_FLOW_STRICT: + command = OFPFC_DELETE_STRICT; + cmd_str = "DELETE STRICT"; + break; + + case ADD_FLOW: + default: + /* the description is from ovs implementation + * If 'command' is given as -2, 'string' may begin with a command name ("add", "modify", "delete", "modify_strict", or "delete_strict"). + * A missing command is treated as "add". */ + // command = OFPFC_ADD; + command = -2; + cmd_str = "ADD"; + break; + } + + struct ofputil_flow_mod fm; + enum ofputil_protocol usable_protocols; + + OFString error(parse_ofp_flow_mod_str(&fm, _flow.c_str(), NULL, + command, &usable_protocols)); + if (error.get()) { + ACA_LOG_ERROR("OFMessage - failed to parse flow: %s, error: %s\n", + _flow.c_str(), error.get()); + return {}; + } + + OFString req_s(ofputil_protocols_to_string(_of_ver)); + OFString usable_s(ofputil_protocols_to_string(usable_protocols)); + if (!(_of_ver & usable_protocols)) { + ACA_LOG_ERROR("OFMessage - flow not supported by requested OF version %s, flow: %s, usable_protocols: %s\n", + req_s.get(), _flow.c_str(), usable_s.get()); + return {}; + } + + auto buf = ofputil_encode_flow_mod((const ofputil_flow_mod *)&fm, _of_ver); + if (buf == nullptr) { + ACA_LOG_ERROR("OFMessage - failed to encode flow_str: %s, OF version: %s, usable_protocols: %s\n", + _flow.c_str(), req_s.get(), usable_s.get()); + return {}; + } + + //ACA_LOG_INFO("encode flow_str: %s, command: %s, type: %d, usable_protocols: %s\n", + // _flow.c_str(), cmd_str.c_str(), (int)(static_cast(buf->data)->type), usable_s.get()); + + // free fm.ofpacts + //OFPact ofpacts(fm.ofpacts); + free(CONST_CAST(struct ofpact *, fm.ofpacts)); + + return std::make_shared(buf); + } + +private: + int _op_type; + std::string _flow; + enum ofputil_protocol _of_ver; +}; + +ofbuf_ptr_t BundleFlowModMessage::pack_open_req() { + struct ofputil_bundle_ctrl_msg bundle_ctrl; + // needs to handshake OFPBCT_OPEN_REQUEST first for ovs to get ready for the following bundle + bundle_ctrl.type = OFPBCT_OPEN_REQUEST; + + // OFPBF_ORDERED ensures flows get programmed in order + // OFPBF_ATOMIC means packet atomic - + // a given packet from an input port or packet-out request should either be processed with none or + // with all of the modifications having been applied + bundle_ctrl.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + auto buf = ofputil_encode_bundle_ctrl_request(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_ctrl); + ofpmsg_update_length(buf); + + // save bundle_id for later use + _bundle_id = bundle_ctrl.bundle_id; + + return std::make_shared(buf); +} + +ofbuf_ptr_t BundleFlowModMessage::pack_commit_req() { + struct ofputil_bundle_ctrl_msg bundle_ctrl; + // bundle_id has to be consistent with open request + bundle_ctrl.bundle_id = _bundle_id; + // OFPBCT_OPEN_REQUEST or bundle flow-mod needs to be followed with an OFPBCT_COMMIT_REQUEST message, + // otherwise error OFPBFC_TIMEOUT will occur + bundle_ctrl.type = OFPBCT_COMMIT_REQUEST; + // flags need to be consistent too + bundle_ctrl.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + auto buf = ofputil_encode_bundle_ctrl_request(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_ctrl); + ofpmsg_update_length(buf); + + return std::make_shared(buf); +} + +std::vector BundleFlowModMessage::pack_flow_mods() { + std::vector ret_buf; + + for (auto of_msg : _flow_mods) { + struct ofputil_bundle_add_msg bundle_flow_mod; + // all flow_mod messages in this bundle share the same bundle id which is generated by ofputil_bundle_ctrl_msg + bundle_flow_mod.bundle_id = _bundle_id; + // by default keep flags consistent with BundleCtrlMessage + bundle_flow_mod.flags = OFPBF_ORDERED | OFPBF_ATOMIC; + + // input is std::shared_ptr of_msg, but need to retrieve data from casting it to std::shared_ptr + auto fm_msg = std::static_pointer_cast(of_msg); + // each flow-mod has a unique xid + fm_msg->set_xid(_fm_xid->fetch_add(1)); + + auto fm_buf = fm_msg->pack(); + // ofputil_bundle_add_msg->msg is (ofpheader*) + bundle_flow_mod.msg = static_cast(fm_buf->data()); + + auto buf = ofputil_encode_bundle_add(ofputil_protocol_to_ofp_version(BUNDLE_OF_VERSION), + &bundle_flow_mod); + + ret_buf.emplace_back(std::make_shared(buf)); + } + + return ret_buf; +} + +void BundleReplyMessage::unpack(void* data) { + struct ofputil_bundle_ctrl_msg bundle_ctrl_reply; + ofputil_decode_bundle_ctrl((ofp_header *)data, &bundle_ctrl_reply); + + _type = bundle_ctrl_reply.type; + _bundle_id = bundle_ctrl_reply.bundle_id; +} + +ofmsg_ptr_t create_add_flow(const std::string& flow, bool bundle) { + return std::make_shared(ADD_FLOW, flow, bundle); +} + +ofmsg_ptr_t create_add_flow(const std::string& flow) { + return std::make_shared(ADD_FLOW, flow); +} + +ofmsg_ptr_t create_mod_flow(const std::string& flow, bool strict) { + int op_type = strict ? MODIFY_FLOW_STRICT : MODIFY_FLOW; + return std::make_shared(op_type, flow); +} + +ofmsg_ptr_t create_del_flow(const std::string& flow, bool strict) { + int op_type = strict ? DELETE_FLOW_STRICT : DELETE_FLOW; + return std::make_shared(op_type, flow); +} + +std::vector create_add_flows(const std::vector& flows) { + std::vector ret; + for (const auto &flow : flows) { + ret.emplace_back(std::make_shared(ADD_FLOW, flow)); + } + + return ret; +} + +ofbuf_ptr_t create_packet_out(const char* option) { + enum ofputil_protocol usable_protocols; + struct ofputil_packet_out po; + char *error; + + error = parse_ofp_packet_out_str(&po, option, NULL, &usable_protocols); + if (error) { + ACA_LOG_ERROR("OFMessage - create_packet_out had error %s\n", error); + } + + auto buf = ofputil_encode_packet_out(&po, DEFAULT_OF_VERSION); + + return std::make_shared(buf); +} \ No newline at end of file diff --git a/src/ovs/ovs_control.cpp b/src/ovs/ovs_control.cpp index 26063f6b..8b529db0 100644 --- a/src/ovs/ovs_control.cpp +++ b/src/ovs/ovs_control.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2008-2017, 2019 Nicira, Inc. -// Copyright 2019 The Alcor Authors - file modified. +// Copyright 2020 Futurewei Cloud - file modified. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ #include #include #include -#include +//#include //#include +//#include #include -#include #include #include @@ -82,15 +82,15 @@ namespace ovs_control { OVS_Control &OVS_Control::get_instance() { - // Instance is destroyed when program exits. - // It is instantiated on first use. - static OVS_Control instance; + // Instance is destroyed when program exits. + // It is instantiated on first use. + static OVS_Control instance; - /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ - allowed_protocols = static_cast(OFPUTIL_P_ANY); - bundle = true; + /* -F, --flow-format: Allowed protocols. By default, any protocol is allowed. */ + allowed_protocols = static_cast(OFPUTIL_P_ANY); + bundle = true; - return instance; + return instance; } int OVS_Control::use_names; @@ -100,65 +100,66 @@ bool OVS_Control::bundle; void OVS_Control::monitor(const char *bridge, const char *opt) { - verbosity = 2; - use_names = -1; + verbosity = 2; + use_names = -1; - /* -P, --packet-in-format: Packet IN format to use in monitor and snoop + /* -P, --packet-in-format: Packet IN format to use in monitor and snoop * commands. Either one of NXPIF_* to force a particular packet_in format, or * -1 to let ovs-ofctl choose the default. */ - int preferred_packet_in_format = -1; + int preferred_packet_in_format = -1; - vconn *vconn; - enum ofputil_protocol usable_protocols = static_cast(OFPUTIL_P_ANY); - bool resume_continuations = false; + vconn *vconn; + enum ofputil_protocol usable_protocols = static_cast(OFPUTIL_P_ANY); + bool resume_continuations = false; - set_allowed_ofp_versions("OpenFlow13"); + set_allowed_ofp_versions("OpenFlow13"); - open_vconn(bridge, &vconn); + open_vconn(bridge, &vconn); - string option; - stringstream iss(opt); + string option; + stringstream iss(opt); - /* If the user wants the invalid_ttl_to_controller feature, limit the + /* If the user wants the invalid_ttl_to_controller feature, limit the * OpenFlow versions to those that support that feature. (Support in * OpenFlow 1.0 is an Open vSwitch extension.) */ - while (iss >> option) { - if (option.compare("invalid_ttl") == 0) { - uint32_t usable_versions = - ((1u << OFP10_VERSION) | (1u << OFP11_VERSION) | (1u << OFP12_VERSION)); - uint32_t allowed_versions = get_allowed_ofp_versions(); - if (!(allowed_versions & usable_versions)) { - struct ds versions = DS_EMPTY_INITIALIZER; - ofputil_format_version_bitmap_names(&versions, usable_versions); - // ovs_fatal(0, "invalid_ttl requires one of the OpenFlow " - // "versions %s but none is enabled (use -O)", - // ds_cstr(&versions)); - ACA_LOG_ERROR("invalid_ttl requires one of the OpenFlow " - "versions %s but none is enabled (use -O)\n", - ds_cstr(&versions)); - } - mask_allowed_ofp_versions(usable_versions); - break; + while (iss >> option) { + if (option.compare("invalid_ttl") == 0) { + uint32_t usable_versions = ((1u << OFP10_VERSION) | (1u << OFP11_VERSION) | + (1u << OFP12_VERSION)); + uint32_t allowed_versions = get_allowed_ofp_versions(); + if (!(allowed_versions & usable_versions)) { + struct ds versions = DS_EMPTY_INITIALIZER; + ofputil_format_version_bitmap_names(&versions, usable_versions); + // ovs_fatal(0, "invalid_ttl requires one of the OpenFlow " + // "versions %s but none is enabled (use -O)", + // ds_cstr(&versions)); + ACA_LOG_ERROR("invalid_ttl requires one of the OpenFlow " + "versions %s but none is enabled (use -O)\n", + ds_cstr(&versions)); + } + mask_allowed_ofp_versions(usable_versions); + break; + } } - } - iss.str(opt); - iss.clear(); + iss.str(opt); + iss.clear(); - while (iss >> option) { - if (isdigit(option[0])) { - struct ofputil_switch_config config; + while (iss >> option) { + if (isdigit(option[0])) { + struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - config.miss_send_len = atoi(option.c_str()); - set_switch_config(vconn, &config); - } else if (option.compare("invalid_ttl") == 0) { - monitor_set_invalid_ttl_to_controller(vconn); - } else if (option.compare(0, 6, "watch:") == 0) { - ofputil_flow_monitor_request fmr; - ofpbuf *msg; - char *error; + fetch_switch_config(vconn, &config); + config.miss_send_len = atoi(option.c_str()); + set_switch_config(vconn, &config); + } else if (option.compare("invalid_ttl") == 0) { + monitor_set_invalid_ttl_to_controller(vconn); + } else if (option.compare(0, 6, "watch:") == 0) { + ofputil_flow_monitor_request fmr; + ofpbuf *msg; + char *error; + /* inactive due to switching ovs dependency error = parse_flow_monitor_request(&fmr, option.substr(6).c_str(), ports_to_accept(bridge), tables_to_accept(bridge), &usable_protocols); @@ -176,514 +177,525 @@ void OVS_Control::monitor(const char *bridge, const char *opt) "the allowed flow formats (%s)", usable_s, allowed_s); } - - msg = ofpbuf_new(0); - ofputil_append_flow_monitor_request(&fmr, msg); - dump_transaction(vconn, msg, bridge); - fflush(stdout); - } else if (option.compare("resume") == 0) { - /* This option is intentionally undocumented because it is meant + */ + + msg = ofpbuf_new(0); + ofputil_append_flow_monitor_request(&fmr, msg); + dump_transaction(vconn, msg, bridge); + fflush(stdout); + } else if (option.compare("resume") == 0) { + /* This option is intentionally undocumented because it is meant * only for testing. */ - resume_continuations = true; - /* Set miss_send_len to ensure that we get packet-ins. */ - struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - config.miss_send_len = UINT16_MAX; - set_switch_config(vconn, &config); - } else { - //ovs_fatal(0, "%s: unsupported \"monitor\" argument", option); - ACA_LOG_ERROR("%s: unsupported monitor argument", option.c_str()); + resume_continuations = true; + /* Set miss_send_len to ensure that we get packet-ins. */ + struct ofputil_switch_config config; + fetch_switch_config(vconn, &config); + config.miss_send_len = UINT16_MAX; + set_switch_config(vconn, &config); + } else { + //ovs_fatal(0, "%s: unsupported \"monitor\" argument", option); + ACA_LOG_ERROR("%s: unsupported monitor argument", option.c_str()); + } } - } - if (preferred_packet_in_format >= 0) { - /* A particular packet-in format was requested, so we must set it. */ - set_packet_in_format( - vconn, static_cast(preferred_packet_in_format), true); - } else { - /* Otherwise, we always prefer NXT_PACKET_IN2. */ - if (!set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT2, false)) { - /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request + if (preferred_packet_in_format >= 0) { + /* A particular packet-in format was requested, so we must set it. */ + set_packet_in_format( + vconn, static_cast(preferred_packet_in_format), true); + } else { + /* Otherwise, we always prefer NXT_PACKET_IN2. */ + if (!set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN2, false)) { + /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request * NXT_PACKET_IN. (Before 2.6, Open vSwitch will accept a request * for NXT_PACKET_IN with OF1.1+, but even after that it still * sends packet-ins in the OpenFlow native format.) */ - if (vconn_get_version(vconn) == OFP10_VERSION) { - set_packet_in_format(vconn, OFPUTIL_PACKET_IN_NXT, false); - } + if (vconn_get_version(vconn) == OFP10_VERSION) { + set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN, false); + } + } } - } - monitor_vconn(vconn, true, resume_continuations, bridge); + monitor_vconn(vconn, true, resume_continuations, bridge); } void OVS_Control::packet_out(const char *bridge, const char *options) { - enum ofputil_protocol usable_protocols; - enum ofputil_protocol protocol; - struct ofputil_packet_out po; - struct vconn *vconn; - struct ofpbuf *opo; - char *error; - - error = parse_ofp_packet_out_str(&po, options, ports_to_accept(bridge), - tables_to_accept(bridge), &usable_protocols); - if (error) { - //ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - } - protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); - opo = ofputil_encode_packet_out(&po, protocol); - transact_noreply(vconn, opo); - vconn_close(vconn); - free(CONST_CAST(void *, po.packet)); - free(po.ofpacts); + enum ofputil_protocol usable_protocols; + enum ofputil_protocol protocol; + struct ofputil_packet_out po; + struct vconn *vconn; + struct ofpbuf *opo; + char *error; + + error = parse_ofp_packet_out_str(&po, options, ports_to_accept(bridge), &usable_protocols); + if (error) { + //ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + } + protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); + opo = ofputil_encode_packet_out(&po, protocol); + transact_noreply(vconn, opo); + vconn_close(vconn); + free(CONST_CAST(void *, po.packet)); + free(po.ofpacts); } int OVS_Control::dump_flows(const char *bridge, const char *flow, bool show_stats) { - ACA_LOG_DEBUG("%s", "OVS_Control::dump_flows ---> Entering\n"); + ACA_LOG_DEBUG("%s", "OVS_Control::dump_flows ---> Entering\n"); - int rc = EXIT_FAILURE; - int n_criteria = 0; + int rc = EXIT_FAILURE; + int n_criteria = 0; - ACA_LOG_INFO("Executing dump_flows on bridge: %s, flow: %s, show_stats: %d\n", - bridge, flow, show_stats); + ACA_LOG_INFO("Executing dump_flows on bridge: %s, flow: %s, show_stats: %d\n", + bridge, flow, show_stats); - auto openflow_client_start = chrono::steady_clock::now(); + auto openflow_client_start = chrono::steady_clock::now(); - if (!n_criteria && !should_show_names() && show_stats) { - dump_flows__(bridge, flow, false); - rc = EXIT_SUCCESS; - } else { - ofputil_flow_stats_request fsr; - enum ofputil_protocol protocol; - struct vconn *vconn; + if (!n_criteria && !should_show_names() && show_stats) { + dump_flows__(bridge, flow, false); + rc = EXIT_SUCCESS; + } else { + ofputil_flow_stats_request fsr; + enum ofputil_protocol protocol; + struct vconn *vconn; + + vconn = prepare_dump_flows(bridge, flow, false, &fsr, &protocol); + struct ofputil_flow_stats *fses; + size_t n_fses; + run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses), "dump flows"); + + struct ds s = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < n_fses; i++) { + ds_clear(&s); + //ofputil_flow_stats_format(&s, &fses[i], ports_to_show(bridge), tables_to_show(bridge), + // //ports_to_show(ctx->argv[1]), + // //tables_to_show(ctx->argv[1]), + // show_stats); + //ACA_LOG_DEBUG(" %s\n", ds_cstr(&s)); + } + if (n_fses > 0) + rc = EXIT_SUCCESS; - vconn = prepare_dump_flows(bridge, flow, false, &fsr, &protocol); - struct ofputil_flow_stats *fses; - size_t n_fses; - run(vconn_dump_flows(vconn, &fsr, protocol, &fses, &n_fses), "dump flows"); - - struct ds s = DS_EMPTY_INITIALIZER; - for (size_t i = 0; i < n_fses; i++) { - ds_clear(&s); - ofputil_flow_stats_format(&s, &fses[i], ports_to_show(bridge), tables_to_show(bridge), - //ports_to_show(ctx->argv[1]), - //tables_to_show(ctx->argv[1]), - show_stats); - ACA_LOG_DEBUG(" %s\n", ds_cstr(&s)); - } - if (n_fses > 0) - rc = EXIT_SUCCESS; + ds_destroy(&s); - ds_destroy(&s); + for (size_t i = 0; i < n_fses; i++) { + free(CONST_CAST(struct ofpact *, fses[i].ofpacts)); + } + free(fses); - for (size_t i = 0; i < n_fses; i++) { - free(CONST_CAST(struct ofpact *, fses[i].ofpacts)); + vconn_close(vconn); } - free(fses); - vconn_close(vconn); - } + auto openflow_client_end = chrono::steady_clock::now(); - auto openflow_client_end = chrono::steady_clock::now(); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); - auto openflow_client_time_total_time = - cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + g_total_execute_openflow_time += openflow_client_time_total_time; - g_total_execute_openflow_time += openflow_client_time_total_time; + ACA_LOG_INFO("Elapsed time for dump_flows call took: %ld microseconds or %ld milliseconds. rc: %d\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time), rc); - ACA_LOG_INFO("Elapsed time for dump_flows call took: %ld microseconds or %ld milliseconds. rc: %d\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time), rc); + ACA_LOG_DEBUG("OVS_Control::dump_flows <--- Exiting, rc = %d\n", rc); - ACA_LOG_DEBUG("OVS_Control::dump_flows <--- Exiting, rc = %d\n", rc); - - return rc; + return rc; } void OVS_Control::dump_flows__(const char *bridge, const char *flow, bool aggregate) { - struct ofputil_flow_stats_request fsr; - enum ofputil_protocol protocol; - struct vconn *vconn; + struct ofputil_flow_stats_request fsr; + enum ofputil_protocol protocol; + struct vconn *vconn; - vconn = prepare_dump_flows(bridge, flow, aggregate, &fsr, &protocol); - dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol), bridge); - vconn_close(vconn); + vconn = prepare_dump_flows(bridge, flow, aggregate, &fsr, &protocol); + dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol), bridge); + vconn_close(vconn); } vconn *OVS_Control::prepare_dump_flows(const char *bridge, const char *flow, bool aggregate, ofputil_flow_stats_request *fsr, ofputil_protocol *protocolp) { - const char *vconn_name = bridge; - enum ofputil_protocol usable_protocols, protocol; - struct vconn *vconn; - char *error; - - // const char *match = argc > 2 ? argv[2] : ""; - const char *match = flow; - const struct ofputil_port_map *port_map = *match ? ports_to_accept(vconn_name) : NULL; - const struct ofputil_table_map *table_map = *match ? tables_to_accept(vconn_name) : NULL; - error = parse_ofp_flow_stats_request_str(fsr, aggregate, match, port_map, - table_map, &usable_protocols); - if (error) { - //ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - } + const char *vconn_name = bridge; + enum ofputil_protocol usable_protocols, protocol; + struct vconn *vconn; + char *error; + + // const char *match = argc > 2 ? argv[2] : ""; + const char *match = flow; + const struct ofputil_port_map *port_map = *match ? ports_to_accept(vconn_name) : NULL; + //const struct ofputil_table_map *table_map = *match ? tables_to_accept(vconn_name) : NULL; + error = parse_ofp_flow_stats_request_str(fsr, aggregate, match, port_map, &usable_protocols); + if (error) { + //ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + } - protocol = open_vconn(vconn_name, &vconn); - *protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); - return vconn; + protocol = open_vconn(vconn_name, &vconn); + *protocolp = set_protocol_for_flow_dump(vconn, protocol, usable_protocols); + return vconn; } enum ofputil_protocol OVS_Control::set_protocol_for_flow_dump(vconn *vconn, ofputil_protocol cur_protocol, ofputil_protocol usable_protocols) { - char *usable_s; - int i; - - for (i = 0; i < (int)ofputil_n_flow_dump_protocols; i++) { - enum ofputil_protocol f = ofputil_flow_dump_protocols[i]; - if (f & usable_protocols & allowed_protocols && try_set_protocol(vconn, f, &cur_protocol)) { - return f; + char *usable_s; + int i; + + for (i = 0; i < (int)ofputil_n_flow_dump_protocols; i++) { + enum ofputil_protocol f = ofputil_flow_dump_protocols[i]; + if (f & usable_protocols & allowed_protocols && + try_set_protocol(vconn, f, &cur_protocol)) { + return f; + } } - } - usable_s = ofputil_protocols_to_string(usable_protocols); - if (usable_protocols & allowed_protocols) { - // ovs_fatal(0, "switch does not support any of the usable flow " - // "formats (%s)", usable_s); - ACA_LOG_ERROR("switch does not support any of the usable flow " - "formats (%s)", - usable_s); - } else { - char *allowed_s = ofputil_protocols_to_string(allowed_protocols); - // ovs_fatal(0, "none of the usable flow formats (%s) is among the " - // "allowed flow formats (%s)", usable_s, allowed_s); - ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " - "allowed flow formats (%s)", - usable_s, allowed_s); - } - return (ofputil_protocol)0; + usable_s = ofputil_protocols_to_string(usable_protocols); + if (usable_protocols & allowed_protocols) { + // ovs_fatal(0, "switch does not support any of the usable flow " + // "formats (%s)", usable_s); + ACA_LOG_ERROR("switch does not support any of the usable flow " + "formats (%s)", + usable_s); + } else { + char *allowed_s = ofputil_protocols_to_string(allowed_protocols); + // ovs_fatal(0, "none of the usable flow formats (%s) is among the " + // "allowed flow formats (%s)", usable_s, allowed_s); + ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " + "allowed flow formats (%s)", + usable_s, allowed_s); + } + return (ofputil_protocol)0; } int OVS_Control::add_flow(const char *bridge, const char *flow) { - return flow_mod(bridge, flow, OFPFC_ADD); + return flow_mod(bridge, flow, OFPFC_ADD); } int OVS_Control::mod_flows(const char *bridge, const char *flow, bool strict) { - return flow_mod(bridge, flow, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); + return flow_mod(bridge, flow, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY); } int OVS_Control::del_flows(const char *bridge, const char *flow, bool strict) { - return flow_mod(bridge, flow, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); + return flow_mod(bridge, flow, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); } int OVS_Control::flow_mod(const char *bridge, const char *flow, unsigned short int command) { - ACA_LOG_DEBUG("%s", "OVS_Control::flow_mod ---> Entering\n"); - - struct ofputil_flow_mod fm; - char *error; - enum ofputil_protocol usable_protocols; - int rc; - - ACA_LOG_INFO("Executing flow_mod on bridge: %s, flow: %s, command: %d\n", - bridge, flow, command); - - auto openflow_client_start = chrono::steady_clock::now(); - error = parse_ofp_flow_mod_str(&fm, flow, ports_to_accept(bridge), - tables_to_accept(bridge), command, &usable_protocols); - if (error) { - // ovs_fatal(0, "%s", error); - ACA_LOG_ERROR("%s", error); - rc = EXIT_FAILURE; - } else { - // flow_mod__ returns void - std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); - - flow_mod__(bridge, &fm, 1, usable_protocols); - std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); - auto message_total_operation_time = - std::chrono::duration_cast(end - start).count(); - ACA_LOG_DEBUG("[flow_mod] Start flow_mod__ at: [%ld], finished at: [%ld]\nElapsed time for flow_mod__ took: %ld microseconds or %ld milliseconds\n", - start, end, message_total_operation_time, - (message_total_operation_time / 1000)); - rc = EXIT_SUCCESS; - } + ACA_LOG_DEBUG("%s", "OVS_Control::flow_mod ---> Entering\n"); + + struct ofputil_flow_mod fm; + char *error; + enum ofputil_protocol usable_protocols; + int rc; - auto openflow_client_end = chrono::steady_clock::now(); + ACA_LOG_INFO("Executing flow_mod on bridge: %s, flow: %s, command: %d\n", + bridge, flow, command); - auto openflow_client_time_total_time = - cast_to_microseconds(openflow_client_end - openflow_client_start).count(); + auto openflow_client_start = chrono::steady_clock::now(); - g_total_execute_openflow_time += openflow_client_time_total_time; + error = parse_ofp_flow_mod_str(&fm, flow, ports_to_accept(bridge), command, &usable_protocols); + if (error) { + // ovs_fatal(0, "%s", error); + ACA_LOG_ERROR("%s", error); + rc = EXIT_FAILURE; + } else { + // flow_mod__ returns void + std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); + + flow_mod__(bridge, &fm, 1, usable_protocols); + std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); + auto message_total_operation_time = + std::chrono::duration_cast(end - start).count(); + ACA_LOG_DEBUG("[flow_mod] Start flow_mod__ at: [%ld], finished at: [%ld]\nElapsed time for flow_mod__ took: %ld microseconds or %ld milliseconds\n", + start, end, message_total_operation_time, + (message_total_operation_time / 1000)); + rc = EXIT_SUCCESS; + } - ACA_LOG_INFO("Elapsed time for flow_mod call took: %ld microseconds or %ld milliseconds. rc: %d\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time), rc); + auto openflow_client_end = chrono::steady_clock::now(); - ACA_LOG_DEBUG("OVS_Control::flow_mod <--- Exiting, rc = %d\n", rc); + auto openflow_client_time_total_time = + cast_to_microseconds(openflow_client_end - openflow_client_start).count(); - return rc; + g_total_execute_openflow_time += openflow_client_time_total_time; + + ACA_LOG_INFO("Elapsed time for flow_mod call took: %ld microseconds or %ld milliseconds. rc: %d\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time), rc); + + ACA_LOG_DEBUG("OVS_Control::flow_mod <--- Exiting, rc = %d\n", rc); + + return rc; } void OVS_Control::flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol protocol; - struct vconn *vconn; - size_t i; + enum ofputil_protocol protocol; + struct vconn *vconn; + size_t i; - if (bundle) { - bundle_flow_mod__(remote, fms, n_fms, usable_protocols); - return; - } + if (bundle) { + bundle_flow_mod__(remote, fms, n_fms, usable_protocols); + return; + } - protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); - for (i = 0; i < n_fms; i++) { - struct ofputil_flow_mod *fm = &fms[i]; + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; - transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); - free(CONST_CAST(struct ofpact *, fm->ofpacts)); - minimatch_destroy(&fm->match); - } - vconn_close(vconn); + transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + //free(&fm->match); + } + vconn_close(vconn); } void OVS_Control::bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol protocol; - struct vconn *vconn; - struct ovs_list requests; - size_t i; + enum ofputil_protocol protocol; + struct vconn *vconn; + char *usable_s; + struct ovs_list requests; + size_t i; - ovs_list_init(&requests); + ovs_list_init(&requests); - /* Bundles need OpenFlow 1.3+. */ - // usable_protocols &= OFPUTIL_P_OF13_UP; - protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + /* Bundles need OpenFlow 1.3+. */ + // usable_protocols &= OFPUTIL_P_OF13_UP; + protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); + usable_s = ofputil_protocols_to_string(protocol); + ACA_LOG_INFO("vconn uses ofp protocol (%s)\n", + usable_s); - for (i = 0; i < n_fms; i++) { - struct ofputil_flow_mod *fm = &fms[i]; - struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol); + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; + struct ofpbuf *request = ofputil_encode_flow_mod(fm, protocol); - ovs_list_push_back(&requests, &request->list_node); - free(CONST_CAST(struct ofpact *, fm->ofpacts)); - minimatch_destroy(&fm->match); - } + ovs_list_push_back(&requests, &request->list_node); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + //free(&fm->match); + } - bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); - ofpbuf_list_delete(&requests); - vconn_close(vconn); + bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); + ofpbuf_list_delete(&requests); + vconn_close(vconn); } enum ofputil_protocol OVS_Control::open_vconn_for_flow_mod(const char *remote, vconn **vconnp, enum ofputil_protocol usable_protocols) { - enum ofputil_protocol cur_protocol; - char *usable_s; - int i; + enum ofputil_protocol cur_protocol; + char *usable_s; + int i; - if (!(usable_protocols & allowed_protocols)) { - char *allowed_s = ofputil_protocols_to_string(allowed_protocols); - usable_s = ofputil_protocols_to_string(usable_protocols); - // ovs_fatal(0, "none of the usable flow formats (%s) is among the " - // "allowed flow formats (%s)", usable_s, allowed_s); - ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " - "allowed flow formats (%s)", - usable_s, allowed_s); - } + if (!(usable_protocols & allowed_protocols)) { + char *allowed_s = ofputil_protocols_to_string(allowed_protocols); + usable_s = ofputil_protocols_to_string(usable_protocols); + // ovs_fatal(0, "none of the usable flow formats (%s) is among the " + // "allowed flow formats (%s)", usable_s, allowed_s); + ACA_LOG_ERROR("none of the usable flow formats (%s) is among the " + "allowed flow formats (%s)", + usable_s, allowed_s); + } - /* If the initial flow format is allowed and usable, keep it. */ - cur_protocol = open_vconn(remote, vconnp); - if (usable_protocols & allowed_protocols & cur_protocol) { - return cur_protocol; - } + /* If the initial flow format is allowed and usable, keep it. */ + cur_protocol = open_vconn(remote, vconnp); + if (usable_protocols & allowed_protocols & cur_protocol) { + return cur_protocol; + } - /* Otherwise try each flow format in turn. */ - for (i = 0; i < (int)sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { - enum ofputil_protocol f = (ofputil_protocol)(1 << i); + /* Otherwise try each flow format in turn. */ + for (i = 0; i < (int)sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { + enum ofputil_protocol f = (ofputil_protocol)(1 << i); - if (f != cur_protocol && f & usable_protocols & allowed_protocols && - try_set_protocol(*vconnp, f, &cur_protocol)) { - return f; + if (f != cur_protocol && f & usable_protocols & allowed_protocols && + try_set_protocol(*vconnp, f, &cur_protocol)) { + return f; + } } - } - usable_s = ofputil_protocols_to_string(usable_protocols); - // ovs_fatal(0, "switch does not support any of the usable flow " - // "formats (%s)", usable_s); - ACA_LOG_ERROR("switch does not support any of the usable flow " - "formats (%s)", - usable_s); - return (ofputil_protocol)0; + usable_s = ofputil_protocols_to_string(usable_protocols); + // ovs_fatal(0, "switch does not support any of the usable flow " + // "formats (%s)", usable_s); + ACA_LOG_ERROR("switch does not support any of the usable flow " + "formats (%s)", + usable_s); + return (ofputil_protocol)0; } /* Returns the port number corresponding to 'port_name' (which may be a port * name or number) within the switch 'vconn_name'. */ ofp_port_t OVS_Control::str_to_port_no(const char *vconn_name, const char *port_name) { - ofp_port_t port_no; - if (ofputil_port_from_string(port_name, NULL, &port_no) || - ofputil_port_from_string(port_name, ports_to_accept(vconn_name), &port_no)) { - return port_no; - } - // ovs_fatal(0, "%s: unknown port `%s'", vconn_name, port_name); - ACA_LOG_ERROR("%s: unknown port `%s'", vconn_name, port_name); - return (ofputil_protocol)0; + ofp_port_t port_no; + if (ofputil_port_from_string(port_name, NULL, &port_no) || + ofputil_port_from_string(port_name, ports_to_accept(vconn_name), &port_no)) { + return port_no; + } + // ovs_fatal(0, "%s: unknown port `%s'", vconn_name, port_name); + ACA_LOG_ERROR("%s: unknown port `%s'", vconn_name, port_name); + return (ofputil_protocol)0; } bool OVS_Control::try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, enum ofputil_protocol *cur) { - for (;;) { - struct ofpbuf *request, *reply; - enum ofputil_protocol next; + for (;;) { + struct ofpbuf *request, *reply; + enum ofputil_protocol next; - request = ofputil_encode_set_protocol(*cur, want, &next); - if (!request) { - return *cur == want; - } + request = ofputil_encode_set_protocol(*cur, want, &next); + if (!request) { + return *cur == want; + } - run(vconn_transact_noreply(vconn, request, &reply), "talking to %s", - vconn_get_name(vconn)); - if (reply) { - char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2); - VLOG_DBG("%s: failed to set protocol, switch replied: %s", vconn_get_name(vconn), s); - free(s); - ofpbuf_delete(reply); - return false; - } + run(vconn_transact_noreply(vconn, request, &reply), "talking to %s", + vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, NULL, 2); + VLOG_DBG("%s: failed to set protocol, switch replied: %s", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + return false; + } - *cur = next; - } + *cur = next; + } } void OVS_Control::fetch_switch_config(vconn *vconn, ofputil_switch_config *config) { - struct ofpbuf *request; - struct ofpbuf *reply; - enum ofptype type; + struct ofpbuf *request; + struct ofpbuf *reply; + enum ofptype type; - request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, vconn_get_version(vconn), 0); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); + request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, vconn_get_version(vconn), 0); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); - if (ofptype_decode(&type, (ofp_header *)reply->data) || type != OFPTYPE_GET_CONFIG_REPLY) { - // ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn)); - ACA_LOG_ERROR("%s: bad reply to config request", vconn_get_name(vconn)); - } - ofputil_decode_get_config_reply((ofp_header *)reply->data, config); - ofpbuf_delete(reply); + if (ofptype_decode(&type, (ofp_header *)reply->data) || type != OFPTYPE_GET_CONFIG_REPLY) { + // ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn)); + ACA_LOG_ERROR("%s: bad reply to config request", vconn_get_name(vconn)); + } + ofputil_decode_get_config_reply((ofp_header *)reply->data, config); + ofpbuf_delete(reply); } void OVS_Control::set_switch_config(vconn *vconn, const ofputil_switch_config *config) { - ofp_version version = static_cast(vconn_get_version(vconn)); - transact_noreply(vconn, ofputil_encode_set_config(config, version)); + ofp_version version = static_cast(vconn_get_version(vconn)); + transact_noreply(vconn, ofputil_encode_set_config(config, version)); } int OVS_Control::open_vconn_socket(const char *name, vconn **vconnp) { - char vconn_name[50]; - int error; - - sprintf(vconn_name, "unix:%s", name); - error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp); - if (error && error != ENOENT) { - // ovs_fatal(0, "%s: failed to open socket (%s)", name, - // ovs_strerror(error)); - ACA_LOG_ERROR("%s: failed to open socket (%s)", name, ovs_strerror(error)); - } - // free(vconn_name); - return error; + char vconn_name[50]; + int error; + + sprintf(vconn_name, "unix:%s", name); + error = vconn_open(vconn_name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp); + if (error && error != ENOENT) { + // ovs_fatal(0, "%s: failed to open socket (%s)", name, + // ovs_strerror(error)); + ACA_LOG_ERROR("%s: failed to open socket (%s)", name, ovs_strerror(error)); + } + // free(vconn_name); + return error; } enum ofputil_protocol OVS_Control::open_vconn(const char *name, vconn **vconnp) { - const char *suffix = "mgmt"; - char *datapath_name, *datapath_type; - enum ofputil_protocol protocol; - char bridge_path[50] = "", socket_name[50] = ""; - int version; - int error; - - sprintf(bridge_path, "%s/%s.%s", ovs_rundir(), name, suffix); - dp_parse_name(name, &datapath_name, &datapath_type); - sprintf(socket_name, "%s/%s.%s", ovs_rundir(), datapath_name, suffix); - free(datapath_name); - free(datapath_type); - if (strchr(name, ':')) { - run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp), - "connecting to %s", name); - } else if (!open_vconn_socket(name, vconnp)) { - /* Fall Through. */ - } else if (!open_vconn_socket(bridge_path, vconnp)) { - /* Fall Through. */ - } else if (!open_vconn_socket(socket_name, vconnp)) { - /* Fall Through. */ - } else { - // free(bridge_path); - // free(socket_name); - // ovs_fatal(0, "%s is not a bridge or a socket", name); - ACA_LOG_ERROR("%s is not a bridge or a socket", name); - } + const char *suffix = "mgmt"; + char *datapath_name, *datapath_type; + enum ofputil_protocol protocol; + char bridge_path[50] = "", socket_name[50] = ""; + int version; + int error; + + // ovs_rundir() returns "/usr/local/var/run/openvswitch/", on some machine's ovs version it is not applicable + //sprintf(bridge_path, "%s/%s.%s", ovs_rundir(), name, suffix); + sprintf(bridge_path, "%s/%s.%s", "/var/run/openvswitch/", name, suffix); + ACA_LOG_INFO("bridge path is %s\n", bridge_path); + dp_parse_name(name, &datapath_name, &datapath_type); + //sprintf(socket_name, "%s/%s.%s", ovs_rundir(), datapath_name, suffix); + sprintf(socket_name, "%s/%s.%s", "/var/run/openvswitch/", datapath_name, suffix); + ACA_LOG_INFO("socket name is %s\n", socket_name); + free(datapath_name); + free(datapath_type); + + if (strchr(name, ':')) { + run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp), + "connecting to %s\n", name); + } else if (!open_vconn_socket(name, vconnp)) { + // Fall Through. + } else if (!open_vconn_socket(bridge_path, vconnp)) { + // Fall Through. + } else if (!open_vconn_socket(socket_name, vconnp)) { + // Fall Through. + } else { + // free(bridge_path); + // free(socket_name); + // ovs_fatal(0, "%s is not a bridge or a socket", name); + ACA_LOG_ERROR("%s is not a bridge or a socket", name); + } - // if (target == SNOOP) { - // vconn_set_recv_any_version(*vconnp); - // } + // if (target == SNOOP) { + // vconn_set_recv_any_version(*vconnp); + // } - // free(bridge_path); - // free(socket_name); + // free(bridge_path); + // free(socket_name); - VLOG_DBG("connecting to %s", vconn_get_name(*vconnp)); - error = vconn_connect_block(*vconnp, -1); - if (error) { - // ovs_fatal(0, "%s: failed to connect to socket (%s)", name, - // ovs_strerror(error)); - ACA_LOG_ERROR("%s: failed to connect to socket (%s)", name, ovs_strerror(error)); - } + ACA_LOG_INFO("connecting to %s\n", vconn_get_name(*vconnp)); + error = vconn_connect_block(*vconnp); + if (error) { + // ovs_fatal(0, "%s: failed to connect to socket (%s)", name, + // ovs_strerror(error)); + ACA_LOG_ERROR("%s: failed to connect to socket (%s)", name, ovs_strerror(error)); + } - version = vconn_get_version(*vconnp); - protocol = ofputil_protocol_from_ofp_version(static_cast(version)); - if (!protocol) { - // ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x", - // name, version); - ACA_LOG_ERROR("%s: unsupported OpenFlow version 0x%02x", name, version); - } - return protocol; + version = vconn_get_version(*vconnp); + protocol = ofputil_protocol_from_ofp_version(static_cast(version)); + if (!protocol) { + // ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x", + // name, version); + ACA_LOG_ERROR("%s: unsupported OpenFlow version 0x%02x", name, version); + } + return protocol; } int OVS_Control::monitor_set_invalid_ttl_to_controller(vconn *vconn) { - struct ofputil_switch_config config; + struct ofputil_switch_config config; - fetch_switch_config(vconn, &config); - if (!config.invalid_ttl_to_controller) { - config.invalid_ttl_to_controller = 1; - set_switch_config(vconn, &config); + fetch_switch_config(vconn, &config); + if (!config.invalid_ttl_to_controller) { + config.invalid_ttl_to_controller = 1; + set_switch_config(vconn, &config); - /* Then retrieve the configuration to see if it really took. OpenFlow + /* Then retrieve the configuration to see if it really took. OpenFlow * has ill-defined error reporting for bad flags, so this is about the * best we can do. */ - fetch_switch_config(vconn, &config); - if (!config.invalid_ttl_to_controller) { - // ovs_fatal(0, "setting invalid_ttl_to_controller failed (this " - // "switch probably doesn't support this flag)"); - ACA_LOG_ERROR("%s", "setting invalid_ttl_to_controller failed (this " - "switch probably doesn't support this flag)"); + fetch_switch_config(vconn, &config); + if (!config.invalid_ttl_to_controller) { + // ovs_fatal(0, "setting invalid_ttl_to_controller failed (this " + // "switch probably doesn't support this flag)"); + ACA_LOG_ERROR("%s", "setting invalid_ttl_to_controller failed (this " + "switch probably doesn't support this flag)"); + } } - } - return 0; + return 0; } /* Converts hex digits in 'hex' to an OpenFlow message in '*msgp'. The @@ -691,30 +703,30 @@ int OVS_Control::monitor_set_invalid_ttl_to_controller(vconn *vconn) * an error message and stores NULL in '*msgp'. */ const char *OVS_Control::openflow_from_hex(const char *hex, ofpbuf **msgp) { - struct ofp_header *oh; - struct ofpbuf *msg; + struct ofp_header *oh; + struct ofpbuf *msg; - msg = ofpbuf_new(strlen(hex) / 2); - *msgp = NULL; + msg = ofpbuf_new(strlen(hex) / 2); + *msgp = NULL; - if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') { - ofpbuf_delete(msg); - return "Trailing garbage in hex data"; - } + if (ofpbuf_put_hex(msg, hex, NULL)[0] != '\0') { + ofpbuf_delete(msg); + return "Trailing garbage in hex data"; + } - if (msg->size < sizeof(struct ofp_header)) { - ofpbuf_delete(msg); - return "Message too short for OpenFlow"; - } + if (msg->size < sizeof(struct ofp_header)) { + ofpbuf_delete(msg); + return "Message too short for OpenFlow"; + } - oh = (ofp_header *)msg->data; - if (msg->size != ntohs(oh->length)) { - ofpbuf_delete(msg); - return "Message size does not match length in OpenFlow header"; - } + oh = (ofp_header *)msg->data; + if (msg->size != ntohs(oh->length)) { + ofpbuf_delete(msg); + return "Message size does not match length in OpenFlow header"; + } - *msgp = msg; - return NULL; + *msgp = msg; + return NULL; } /* Prints to stderr all of the messages received on 'vconn'. @@ -727,426 +739,422 @@ const char *OVS_Control::openflow_from_hex(const char *hex, ofpbuf **msgp) void OVS_Control::monitor_vconn(vconn *vconn, bool reply_to_echo_requests, bool resume_continuations, const char *bridge_) { - static const char *bridge = bridge_; - bool timestamp = true; - struct barrier_aux barrier_aux = { vconn, NULL }; - struct unixctl_server *server; - bool exiting = false; - bool blocked = false; - int error; - - // Put all functions used by daemon in a local struct. - struct X { - static void ofctl_exit(unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) - { - bool *exiting = (bool *)exiting_; - *exiting = true; - unixctl_command_reply(conn, NULL); - } - - static void ofctl_send(unixctl_conn *conn, int argc, const char *argv[], void *vconn_) - { - struct vconn *vconn = (struct vconn *)vconn_; - struct ds reply; - bool ok; - int i; - - ok = true; - ds_init(&reply); - for (i = 1; i < argc; i++) { - const char *error_msg; - struct ofpbuf *msg; - int error; - - error_msg = OVS_Control().openflow_from_hex(argv[i], &msg); - if (error_msg) { - ds_put_format(&reply, "%s\n", error_msg); - ok = false; - continue; + static const char *bridge = bridge_; + bool timestamp = true; + struct barrier_aux barrier_aux = { vconn, NULL }; + struct unixctl_server *server; + bool exiting = false; + bool blocked = false; + int error; + + // Put all functions used by daemon in a local struct. + struct X { + static void ofctl_exit(unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *exiting_) + { + bool *exiting = (bool *)exiting_; + *exiting = true; + unixctl_command_reply(conn, NULL); } - fprintf(stderr, "send: "); - ofp_print(stderr, msg->data, msg->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity); - OVS_Control().ports_to_show(bridge), - OVS_Control().tables_to_show(bridge), verbosity); - error = vconn_send_block(vconn, msg); - if (error) { - ofpbuf_delete(msg); - ds_put_format(&reply, "%s\n", ovs_strerror(error)); - ok = false; - } else { - ds_put_cstr(&reply, "sent\n"); + static void ofctl_send(unixctl_conn *conn, int argc, const char *argv[], void *vconn_) + { + struct vconn *vconn = (struct vconn *)vconn_; + struct ds reply; + bool ok; + int i; + + ok = true; + ds_init(&reply); + for (i = 1; i < argc; i++) { + const char *error_msg; + struct ofpbuf *msg; + int error; + + error_msg = OVS_Control().openflow_from_hex(argv[i], &msg); + if (error_msg) { + ds_put_format(&reply, "%s\n", error_msg); + ok = false; + continue; + } + + fprintf(stderr, "send: "); + ofp_print(stderr, msg->data, msg->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity); + OVS_Control().ports_to_show(bridge), verbosity); + error = vconn_send_block(vconn, msg); + if (error) { + ofpbuf_delete(msg); + ds_put_format(&reply, "%s\n", ovs_strerror(error)); + ok = false; + } else { + ds_put_cstr(&reply, "sent\n"); + } + } + + if (ok) { + unixctl_command_reply(conn, ds_cstr(&reply)); + } else { + unixctl_command_reply_error(conn, ds_cstr(&reply)); + } + ds_destroy(&reply); } - } - if (ok) { - unixctl_command_reply(conn, ds_cstr(&reply)); - } else { - unixctl_command_reply_error(conn, ds_cstr(&reply)); - } - ds_destroy(&reply); - } + static void unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc, + const char *argv[], void *vconn_) + { + struct vconn *vconn = (struct vconn *)vconn_; + enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version( + static_cast(vconn_get_version(vconn))); + struct ds reply = DS_EMPTY_INITIALIZER; + bool ok = true; + + enum ofputil_protocol usable_protocols; + struct ofputil_packet_out po; + char *error_msg; + + error_msg = parse_ofp_packet_out_str( + &po, argv[1], + // ports_to_accept(vconn_get_name(vconn)), + // tables_to_accept(vconn_get_name(vconn)), + OVS_Control().ports_to_accept(bridge), &usable_protocols); + if (error_msg) { + ds_put_format(&reply, "%s\n", error_msg); + free(error_msg); + ok = false; + } - static void unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc, - const char *argv[], void *vconn_) - { - struct vconn *vconn = (struct vconn *)vconn_; - enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version( - static_cast(vconn_get_version(vconn))); - struct ds reply = DS_EMPTY_INITIALIZER; - bool ok = true; - - enum ofputil_protocol usable_protocols; - struct ofputil_packet_out po; - char *error_msg; - - error_msg = parse_ofp_packet_out_str(&po, argv[1], - // ports_to_accept(vconn_get_name(vconn)), - // tables_to_accept(vconn_get_name(vconn)), - OVS_Control().ports_to_accept(bridge), - OVS_Control().tables_to_accept(bridge), - &usable_protocols); - if (error_msg) { - ds_put_format(&reply, "%s\n", error_msg); - free(error_msg); - ok = false; - } + if (ok && !(usable_protocols & protocol)) { + ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n"); + ok = false; + } - if (ok && !(usable_protocols & protocol)) { - ds_put_format(&reply, "PACKET_OUT actions are incompatible with the OpenFlow connection.\n"); - ok = false; - } + if (ok) { + struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol); + + ofp_print(stderr, msg->data, msg->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity); + OVS_Control().ports_to_show(bridge), verbosity); + int error = vconn_send_block(vconn, msg); + if (error) { + ofpbuf_delete(msg); + ds_put_format(&reply, "%s\n", ovs_strerror(error)); + ok = false; + } + } + + if (ok) { + unixctl_command_reply(conn, ds_cstr(&reply)); + } else { + unixctl_command_reply_error(conn, ds_cstr(&reply)); + } + ds_destroy(&reply); - if (ok) { - struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol); - - ofp_print(stderr, msg->data, msg->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity); - OVS_Control().ports_to_show(bridge), - OVS_Control().tables_to_show(bridge), verbosity); - int error = vconn_send_block(vconn, msg); - if (error) { - ofpbuf_delete(msg); - ds_put_format(&reply, "%s\n", ovs_strerror(error)); - ok = false; + if (!error_msg) { + free(CONST_CAST(void *, po.packet)); + free(po.ofpacts); + } } - } - if (ok) { - unixctl_command_reply(conn, ds_cstr(&reply)); - } else { - unixctl_command_reply_error(conn, ds_cstr(&reply)); - } - ds_destroy(&reply); + static void ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux_) + { + struct barrier_aux *aux = (struct barrier_aux *)aux_; + struct ofpbuf *msg; + int error; - if (!error_msg) { - free(CONST_CAST(void *, po.packet)); - free(po.ofpacts); - } - } + if (aux->conn) { + unixctl_command_reply_error(conn, "already waiting for barrier reply"); + return; + } - static void ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux_) - { - struct barrier_aux *aux = (struct barrier_aux *)aux_; - struct ofpbuf *msg; - int error; + msg = ofputil_encode_barrier_request( + static_cast(vconn_get_version(aux->vconn))); + error = vconn_send_block(aux->vconn, msg); + if (error) { + ofpbuf_delete(msg); + unixctl_command_reply_error(conn, ovs_strerror(error)); + } else { + aux->conn = conn; + } + } - if (aux->conn) { - unixctl_command_reply_error(conn, "already waiting for barrier reply"); - return; - } + static void ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) + { + int fd; - msg = ofputil_encode_barrier_request( - static_cast(vconn_get_version(aux->vconn))); - error = vconn_send_block(aux->vconn, msg); - if (error) { - ofpbuf_delete(msg); - unixctl_command_reply_error(conn, ovs_strerror(error)); - } else { - aux->conn = conn; - } - } + fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (fd < 0) { + unixctl_command_reply_error(conn, ovs_strerror(errno)); + return; + } - static void ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) - { - int fd; + fflush(stderr); + dup2(fd, STDERR_FILENO); + close(fd); + unixctl_command_reply(conn, NULL); + } - fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (fd < 0) { - unixctl_command_reply_error(conn, ovs_strerror(errno)); - return; - } + static void ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *blocked_) + { + bool *blocked = (bool *)blocked_; - fflush(stderr); - dup2(fd, STDERR_FILENO); - close(fd); - unixctl_command_reply(conn, NULL); - } + if (!*blocked) { + *blocked = true; + unixctl_command_reply(conn, NULL); + } else { + unixctl_command_reply(conn, "already blocking"); + } + } - static void ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) - { - bool *blocked = (bool *)blocked_; + static void ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *blocked_) + { + bool *blocked = (bool *)blocked_; - if (!*blocked) { - *blocked = true; - unixctl_command_reply(conn, NULL); - } else { - unixctl_command_reply(conn, "already blocking"); - } + if (*blocked) { + *blocked = false; + unixctl_command_reply(conn, NULL); + } else { + unixctl_command_reply(conn, "already unblocked"); + } + } + }; + + daemon_save_fd(STDERR_FILENO); + daemonize_start(false); + error = unixctl_server_create(unixctl_path, &server); + if (error) { + // ovs_fatal(error, "failed to create unixctl server"); + ACA_LOG_ERROR("%s", "failed to create unixctl server"); } + unixctl_command_register("exit", "", 0, 0, X::ofctl_exit, &exiting); + unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX, X::ofctl_send, vconn); + unixctl_command_register("ofctl/packet-out", "\"in_port= packet= actions=...\"", + 1, 1, X::unixctl_packet_out, vconn); + unixctl_command_register("ofctl/barrier", "", 0, 0, X::ofctl_barrier, &barrier_aux); + unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1, + X::ofctl_set_output_file, NULL); - static void ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) - { - bool *blocked = (bool *)blocked_; + unixctl_command_register("ofctl/block", "", 0, 0, X::ofctl_block, &blocked); + unixctl_command_register("ofctl/unblock", "", 0, 0, X::ofctl_unblock, &blocked); - if (*blocked) { - *blocked = false; - unixctl_command_reply(conn, NULL); - } else { - unixctl_command_reply(conn, "already unblocked"); - } - } - }; - - daemon_save_fd(STDERR_FILENO); - daemonize_start(false); - error = unixctl_server_create(unixctl_path, &server); - if (error) { - // ovs_fatal(error, "failed to create unixctl server"); - ACA_LOG_ERROR("%s", "failed to create unixctl server"); - } - unixctl_command_register("exit", "", 0, 0, X::ofctl_exit, &exiting); - unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX, X::ofctl_send, vconn); - unixctl_command_register("ofctl/packet-out", "\"in_port= packet= actions=...\"", - 1, 1, X::unixctl_packet_out, vconn); - unixctl_command_register("ofctl/barrier", "", 0, 0, X::ofctl_barrier, &barrier_aux); - unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1, - X::ofctl_set_output_file, NULL); + daemonize_complete(); - unixctl_command_register("ofctl/block", "", 0, 0, X::ofctl_block, &blocked); - unixctl_command_register("ofctl/unblock", "", 0, 0, X::ofctl_unblock, &blocked); + enum ofp_version version = static_cast(vconn_get_version(vconn)); + enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version(version); - daemonize_complete(); + for (;;) { + struct ofpbuf *b; + int retval; - enum ofp_version version = static_cast(vconn_get_version(vconn)); - enum ofputil_protocol protocol = ofputil_protocol_from_ofp_version(version); + unixctl_server_run(server); - for (;;) { - struct ofpbuf *b; - int retval; + while (!blocked) { + enum ofptype type; - unixctl_server_run(server); + retval = vconn_recv(vconn, &b); + if (retval == EAGAIN) { + break; + } + run(retval, "vconn_recv"); - while (!blocked) { - enum ofptype type; + if (timestamp) { + char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ", time_wall_msec(), true); + fputs(s, stderr); + free(s); + } + ofptype_decode(&type, (ofp_header *)b->data); - retval = vconn_recv(vconn, &b); - if (retval == EAGAIN) { - break; - } - run(retval, "vconn_recv"); + ofp_print(stderr, b->data, b->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), verbosity + 2); + ports_to_show(bridge), verbosity + 2); + fflush(stderr); - if (timestamp) { - char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ", time_wall_msec(), true); - fputs(s, stderr); - free(s); - } - ofptype_decode(&type, (ofp_header *)b->data); - - ofp_print(stderr, b->data, b->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), verbosity + 2); - ports_to_show(bridge), tables_to_show(bridge), verbosity + 2); - fflush(stderr); - - switch ((int)type) { - case OFPTYPE_BARRIER_REPLY: - if (barrier_aux.conn) { - unixctl_command_reply(barrier_aux.conn, NULL); - barrier_aux.conn = NULL; - } - break; - - case OFPTYPE_ECHO_REQUEST: - if (reply_to_echo_requests) { - struct ofpbuf *reply; - - reply = ofputil_encode_echo_reply((ofp_header *)b->data); - retval = vconn_send_block(vconn, reply); - if (retval) { - // ovs_fatal(retval, "failed to send echo reply"); - ACA_LOG_ERROR("%s", "failed to send echo reply"); - } - } - break; - - case OFPTYPE_PACKET_IN: - if (resume_continuations) { - struct ofputil_packet_in pin; - struct ofpbuf continuation; - size_t total_lenp; - uint32_t buffer_idp; - - error = ofputil_decode_packet_in((ofp_header *)b->data, true, NULL, NULL, - &pin, &total_lenp, &buffer_idp, &continuation); - uint32_t in_port = pin.flow_metadata.flow.in_port.ofp_port; - /* + switch ((int)type) { + case OFPTYPE_BARRIER_REPLY: + if (barrier_aux.conn) { + unixctl_command_reply(barrier_aux.conn, NULL); + barrier_aux.conn = NULL; + } + break; + + //case OFPTYPE_ECHO_REQUEST: + // if (reply_to_echo_requests) { + // struct ofpbuf *reply; + + // reply = ofputil_encode_echo_reply((ofp_header *)b->data); + // retval = vconn_send_block(vconn, reply); + // if (retval) { + // // ovs_fatal(retval, "failed to send echo reply"); + // ACA_LOG_ERROR("%s", "failed to send echo reply"); + // } + // } + // break; + + case OFPTYPE_PACKET_IN: + if (resume_continuations) { + struct ofputil_packet_in pin; + struct ofpbuf continuation; + size_t total_lenp; + uint32_t buffer_idp; + + error = ofputil_decode_packet_in((ofp_header *)b->data, true, + NULL, NULL, &pin, &total_lenp, + &buffer_idp, &continuation); + uint32_t in_port = pin.flow_metadata.flow.in_port.ofp_port; + /* The pin.packet here has the same memory address, even after multiple calls. If you intent to store it somewhere, it is advised to make a copy of it. */ - ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); - - if (error) { - fprintf(stderr, "decoding packet-in failed: %s", - ofperr_to_string((ofperr)error)); - } else if (continuation.size) { - struct ofpbuf *reply; - - reply = ofputil_encode_resume(&pin, &continuation, protocol); - - fprintf(stderr, "send: "); - ofp_print(stderr, reply->data, reply->size, ports_to_show(bridge), - tables_to_show(bridge), - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - verbosity + 2); - fflush(stderr); - - retval = vconn_send_block(vconn, reply); - if (retval) { - // ovs_fatal(retval, "failed to send NXT_RESUME"); - ACA_LOG_ERROR("%s", "failed to send NXT_RESUME"); + ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); + + if (error) { + fprintf(stderr, "decoding packet-in failed: %s", + ofperr_to_string((ofperr)error)); + } else if (continuation.size) { + struct ofpbuf *reply; + + reply = ofputil_encode_resume(&pin, &continuation, protocol); + + fprintf(stderr, "send: "); + ofp_print(stderr, reply->data, reply->size, ports_to_show(bridge), + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + verbosity + 2); + fflush(stderr); + + retval = vconn_send_block(vconn, reply); + if (retval) { + // ovs_fatal(retval, "failed to send NXT_RESUME"); + ACA_LOG_ERROR("%s", "failed to send NXT_RESUME"); + } + } + } + break; } - } + ofpbuf_delete(b); } - break; - } - ofpbuf_delete(b); - } - if (exiting) { - break; - } - vconn_run(vconn); - vconn_run_wait(vconn); - if (!blocked) { - vconn_recv_wait(vconn); + if (exiting) { + break; + } + vconn_run(vconn); + vconn_run_wait(vconn); + if (!blocked) { + vconn_recv_wait(vconn); + } + unixctl_server_wait(server); + poll_block(); } - unixctl_server_wait(server); - poll_block(); - } - vconn_close(vconn); - unixctl_server_destroy(server); + vconn_close(vconn); + unixctl_server_destroy(server); } void OVS_Control::run(int retval, const char *message, ...) { - if (retval) { - va_list args; + if (retval) { + va_list args; - va_start(args, message); - ovs_fatal_valist(retval, message, args); - } + va_start(args, message); + ovs_fatal_valist(retval, message, args); + } } -bool OVS_Control::set_packet_in_format(vconn *vconn, enum ofputil_packet_in_format packet_in_format, +bool OVS_Control::set_packet_in_format(vconn *vconn, enum nx_packet_in_format packet_in_format, bool must_succeed) { - struct ofpbuf *spif; + struct ofpbuf *spif; - spif = ofputil_encode_set_packet_in_format( - static_cast(vconn_get_version(vconn)), packet_in_format); - if (must_succeed) { - transact_noreply(vconn, spif); - } else { - struct ofpbuf *reply; + //spif = ofputil_encode_set_packet_in_format( + spif = ofputil_make_set_packet_in_format( + static_cast(vconn_get_version(vconn)), packet_in_format); - run(vconn_transact_noreply(vconn, spif, &reply), "talking to %s", vconn_get_name(vconn)); - if (reply) { - char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, 2); - VLOG_DBG("%s: failed to set packet in format to nx_packet_in, " - "controller replied: %s.", - vconn_get_name(vconn), s); - free(s); - ofpbuf_delete(reply); - - return false; + if (must_succeed) { + transact_noreply(vconn, spif); } else { - VLOG_DBG("%s: using user-specified packet in format %s", vconn_get_name(vconn), - ofputil_packet_in_format_to_string(packet_in_format)); + struct ofpbuf *reply; + + run(vconn_transact_noreply(vconn, spif, &reply), "talking to %s", + vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, NULL, 2); + VLOG_DBG("%s: failed to set packet in format to nx_packet_in, " + "controller replied: %s.", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + + return false; + } } - } - return true; + return true; } void OVS_Control::bundle_transact(struct vconn *vconn, struct ovs_list *requests, uint16_t flags) { - struct ovs_list errors; - int retval = vconn_bundle_transact(vconn, requests, flags, &errors); + struct ovs_list errors; + int retval = vconn_bundle_transact(vconn, requests, flags, &errors); - bundle_print_errors(&errors, requests, vconn_get_name(vconn)); + bundle_print_errors(&errors, requests, vconn_get_name(vconn)); - if (retval) { - // ovs_fatal(retval, "talking to %s", vconn_get_name(vconn)); - ACA_LOG_ERROR("talking to %s", vconn_get_name(vconn)); - } + if (retval) { + // ovs_fatal(retval, "talking to %s", vconn_get_name(vconn)); + ACA_LOG_ERROR("talking to %s", vconn_get_name(vconn)); + } } /* Frees the error messages as they are printed. */ void OVS_Control::bundle_print_errors(struct ovs_list *errors, struct ovs_list *requests, const char *vconn_name) { - struct ofpbuf *error, *next; - struct ofpbuf *bmsg; + struct ofpbuf *error, *next; + struct ofpbuf *bmsg; - INIT_CONTAINER(bmsg, requests, list_node); + INIT_CONTAINER(bmsg, requests, list_node); - LIST_FOR_EACH_SAFE(error, next, list_node, errors) - { - const struct ofp_header *error_oh = (ofp_header *)error->data; - ovs_be32 error_xid = error_oh->xid; - enum ofperr ofperr; - struct ofpbuf payload; - - ofperr = ofperr_decode_msg(error_oh, &payload); - if (!ofperr) { - fprintf(stderr, "***decode error***"); - } else { - /* Default to the likely truncated message. */ - const struct ofp_header *ofp_msg = (ofp_header *)payload.data; - size_t msg_len = payload.size; + LIST_FOR_EACH_SAFE(error, next, list_node, errors) + { + const struct ofp_header *error_oh = (ofp_header *)error->data; + ovs_be32 error_xid = error_oh->xid; + enum ofperr ofperr; + struct ofpbuf payload; + + ofperr = ofperr_decode_msg(error_oh, &payload); + if (!ofperr) { + fprintf(stderr, "***decode error***"); + } else { + /* Default to the likely truncated message. */ + const struct ofp_header *ofp_msg = (ofp_header *)payload.data; + size_t msg_len = payload.size; - /* Find the failing message from the requests list to be able to + /* Find the failing message from the requests list to be able to * dump the whole message. We assume the errors are returned in * the same order as in which the messages are sent to get O(n) * rather than O(n^2) processing here. If this heuristics fails we * may print the truncated hexdumps instead. */ - LIST_FOR_EACH_CONTINUE(bmsg, list_node, requests) - { - const struct ofp_header *oh = (ofp_header *)bmsg->data; - - if (oh->xid == error_xid) { - ofp_msg = oh; - msg_len = bmsg->size; - break; + LIST_FOR_EACH_CONTINUE(bmsg, list_node, requests) + { + const struct ofp_header *oh = (ofp_header *)bmsg->data; + + if (oh->xid == error_xid) { + ofp_msg = oh; + msg_len = bmsg->size; + break; + } + } + fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr)); + ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name), verbosity + 1); } - } - fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr)); - ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name), - tables_to_show(vconn_name), verbosity + 1); + ofpbuf_uninit(&payload); + ofpbuf_delete(error); } - ofpbuf_uninit(&payload); - ofpbuf_delete(error); - } - fflush(stderr); + fflush(stderr); } /* Sends 'request', which should be a request that only has a reply if an error @@ -1156,11 +1164,11 @@ void OVS_Control::bundle_print_errors(struct ovs_list *errors, * Destroys 'request'. */ void OVS_Control::transact_noreply(vconn *vconn, ofpbuf *request) { - struct ovs_list requests; + struct ovs_list requests; - ovs_list_init(&requests); - ovs_list_push_back(&requests, &request->list_node); - transact_multiple_noreply(vconn, &requests); + ovs_list_init(&requests); + ovs_list_push_back(&requests, &request->list_node); + transact_multiple_noreply(vconn, &requests); } /* Sends all of the 'requests', which should be requests that only have replies @@ -1170,141 +1178,140 @@ void OVS_Control::transact_noreply(vconn *vconn, ofpbuf *request) * Destroys all of the 'requests'. */ void OVS_Control::transact_multiple_noreply(vconn *vconn, ovs_list *requests) { - struct ofpbuf *reply; - - run(vconn_transact_multiple_noreply(vconn, requests, &reply), "talking to %s", - vconn_get_name(vconn)); - if (reply) { - ofp_print(stderr, reply->data, reply->size, ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), verbosity + 2); - exit(1); - } - ofpbuf_delete(reply); + struct ofpbuf *reply; + + run(vconn_transact_multiple_noreply(vconn, requests, &reply), + "talking to %s", vconn_get_name(vconn)); + if (reply) { + ofp_print(stderr, reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), verbosity + 2); + exit(1); + } + ofpbuf_delete(reply); } void OVS_Control::send_openflow_buffer(vconn *vconn, ofpbuf *buffer) { - run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); + run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); } void OVS_Control::dump_transaction(vconn *vconn, ofpbuf *request, const char *bridge) { - const ofp_header *oh = (ofp_header *)request->data; - if (ofpmsg_is_stat_request(oh)) { - ovs_be32 send_xid = oh->xid; - enum ofpraw request_raw; - enum ofpraw reply_raw; - bool done = false; - - ofpraw_decode_partial(&request_raw, (ofp_header *)request->data, request->size); - reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version); - - send_openflow_buffer(vconn, request); - while (!done) { - ovs_be32 recv_xid; - struct ofpbuf *reply; - - run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - recv_xid = ((struct ofp_header *)reply->data)->xid; - if (send_xid == recv_xid) { - enum ofpraw ofpraw; - ofp_print(stdout, reply->data, reply->size, ports_to_show(bridge), - tables_to_show(bridge), - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - verbosity + 1); - - ofpraw_decode(&ofpraw, (struct ofp_header *)reply->data); - if (ofptype_from_ofpraw(ofpraw) == OFPTYPE_ERROR) { - done = true; - } else if (ofpraw == reply_raw) { - done = !ofpmp_more((struct ofp_header *)reply->data); - } else { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string( - // reply->data, reply->size, - // ports_to_show(vconn_get_name(vconn)), - // tables_to_show(vconn_get_name(vconn)), - // OVS_Control::verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(reply->data, reply->size, - ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), - OVS_Control::verbosity + 1)); + const ofp_header *oh = (ofp_header *)request->data; + if (ofpmsg_is_stat_request(oh)) { + ovs_be32 send_xid = oh->xid; + enum ofpraw request_raw; + enum ofpraw reply_raw; + bool done = false; + + ofpraw_decode_partial(&request_raw, (ofp_header *)request->data, request->size); + reply_raw = ofpraw_stats_request_to_reply(request_raw, oh->version); + + send_openflow_buffer(vconn, request); + while (!done) { + ovs_be32 recv_xid; + struct ofpbuf *reply; + + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); + recv_xid = ((struct ofp_header *)reply->data)->xid; + if (send_xid == recv_xid) { + enum ofpraw ofpraw; + ofp_print(stdout, reply->data, reply->size, ports_to_show(bridge), + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + verbosity + 1); + + ofpraw_decode(&ofpraw, (struct ofp_header *)reply->data); + if (ofptype_from_ofpraw(ofpraw) == OFPTYPE_ERROR) { + done = true; + } else if (ofpraw == reply_raw) { + done = !ofpmp_more((struct ofp_header *)reply->data); + } else { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string( + // reply->data, reply->size, + // ports_to_show(vconn_get_name(vconn)), + // tables_to_show(vconn_get_name(vconn)), + // OVS_Control::verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), + OVS_Control::verbosity + 1)); + } + } else { + VLOG_DBG("received reply with xid %08" PRIx32 " " + "!= expected %08" PRIx32, + recv_xid, send_xid); + } + ofpbuf_delete(reply); } - } else { - VLOG_DBG("received reply with xid %08" PRIx32 " " - "!= expected %08" PRIx32, - recv_xid, send_xid); - } - ofpbuf_delete(reply); + } else { + struct ofpbuf *reply; + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); + ofp_print(stdout, reply->data, reply->size, + ports_to_show(vconn_get_name(vconn)), verbosity + 1); + ofpbuf_delete(reply); } - } else { - struct ofpbuf *reply; - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); - ofp_print(stdout, reply->data, reply->size, ports_to_show(vconn_get_name(vconn)), - tables_to_show(vconn_get_name(vconn)), verbosity + 1); - ofpbuf_delete(reply); - } } bool OVS_Control::str_to_ofp(const char *s, ofp_port_t *ofp_port) { - bool ret; - uint32_t port_; + bool ret; + uint32_t port_; - ret = str_to_uint(s, 10, &port_); - *ofp_port = OFP_PORT_C(port_); + ret = str_to_uint(s, 10, &port_); + *ofp_port = OFP_PORT_C(port_); - return ret; + return ret; } void OVS_Control::port_iterator_fetch_port_desc(port_iterator *pi) { - pi->variant = PI_PORT_DESC; - pi->more = true; + pi->variant = PI_PORT_DESC; + pi->more = true; - struct ofpbuf *rq = ofputil_encode_port_desc_stats_request( - static_cast(vconn_get_version(pi->vconn)), OFPP_ANY); - pi->send_xid = ((struct ofp_header *)rq->data)->xid; - send_openflow_buffer(pi->vconn, rq); + struct ofpbuf *rq = ofputil_encode_port_desc_stats_request( + static_cast(vconn_get_version(pi->vconn)), OFPP_ANY); + pi->send_xid = ((struct ofp_header *)rq->data)->xid; + send_openflow_buffer(pi->vconn, rq); } void OVS_Control::port_iterator_fetch_features(port_iterator *pi) { - pi->variant = PI_FEATURES; - - /* Fetch the switch's ofp_switch_features. */ - enum ofp_version version = static_cast(vconn_get_version(pi->vconn)); - struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0); - run(vconn_transact(pi->vconn, rq, &pi->reply), "talking to %s", vconn_get_name(pi->vconn)); - - enum ofptype type; - if (ofptype_decode(&type, (struct ofp_header *)pi->reply->data) || - type != OFPTYPE_FEATURES_REPLY) { - // ovs_fatal(0, "%s: received bad features reply", - // vconn_get_name(pi->vconn)); - ACA_LOG_ERROR("%s: received bad features reply", vconn_get_name(pi->vconn)); - } - if (!ofputil_switch_features_has_ports(pi->reply)) { - /* The switch features reply does not contain a complete list of ports. + pi->variant = PI_FEATURES; + + /* Fetch the switch's ofp_switch_features. */ + enum ofp_version version = static_cast(vconn_get_version(pi->vconn)); + struct ofpbuf *rq = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, version, 0); + run(vconn_transact(pi->vconn, rq, &pi->reply), "talking to %s", + vconn_get_name(pi->vconn)); + + enum ofptype type; + if (ofptype_decode(&type, (struct ofp_header *)pi->reply->data) || + type != OFPTYPE_FEATURES_REPLY) { + // ovs_fatal(0, "%s: received bad features reply", + // vconn_get_name(pi->vconn)); + ACA_LOG_ERROR("%s: received bad features reply", vconn_get_name(pi->vconn)); + } + if (!ofputil_switch_features_has_ports(pi->reply)) { + /* The switch features reply does not contain a complete list of ports. * Probably, there are more ports than will fit into a single 64 kB * OpenFlow message. Use OFPST_PORT_DESC to get a complete list of * ports. */ - ofpbuf_delete(pi->reply); - pi->reply = NULL; - port_iterator_fetch_port_desc(pi); - return; - } + ofpbuf_delete(pi->reply); + pi->reply = NULL; + port_iterator_fetch_port_desc(pi); + return; + } - struct ofputil_switch_features features; - enum ofperr error = ofputil_pull_switch_features(pi->reply, &features); - if (error) { - // ovs_fatal(0, "%s: failed to decode features reply (%s)", - // vconn_get_name(pi->vconn), ofperr_to_string(error)); - ACA_LOG_ERROR("%s: failed to decode features reply (%s)", - vconn_get_name(pi->vconn), ofperr_to_string(error)); - } + struct ofputil_switch_features features; + enum ofperr error = ofputil_pull_switch_features(pi->reply, &features); + if (error) { + // ovs_fatal(0, "%s: failed to decode features reply (%s)", + // vconn_get_name(pi->vconn), ofperr_to_string(error)); + ACA_LOG_ERROR("%s: failed to decode features reply (%s)", + vconn_get_name(pi->vconn), ofperr_to_string(error)); + } } /* Initializes 'pi' to prepare for iterating through all of the ports on the @@ -1315,13 +1322,13 @@ void OVS_Control::port_iterator_fetch_features(port_iterator *pi) * iterator and thus some ports may be missed or a hang can occur. */ void OVS_Control::port_iterator_init(port_iterator *pi, vconn *vconn) { - memset(pi, 0, sizeof *pi); - pi->vconn = vconn; - if (vconn_get_version(vconn) < OFP13_VERSION) { - port_iterator_fetch_features(pi); - } else { - port_iterator_fetch_port_desc(pi); - } + memset(pi, 0, sizeof *pi); + pi->vconn = vconn; + if (vconn_get_version(vconn) < OFP13_VERSION) { + port_iterator_fetch_features(pi); + } else { + port_iterator_fetch_port_desc(pi); + } } /* Obtains the next port from 'pi'. On success, initializes '*pp' with the @@ -1329,60 +1336,60 @@ void OVS_Control::port_iterator_init(port_iterator *pi, vconn *vconn) * been seen), returns false. */ bool OVS_Control::port_iterator_next(port_iterator *pi, ofputil_phy_port *pp) { - for (;;) { - if (pi->reply) { - int retval = ofputil_pull_phy_port( - static_cast(vconn_get_version(pi->vconn)), pi->reply, pp); - if (!retval) { - return true; - } else if (retval != EOF) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(pi->reply->data, pi->reply->size, - // NULL, NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(pi->reply->data, pi->reply->size, NULL, - NULL, verbosity + 1)); - } - } + for (;;) { + if (pi->reply) { + int retval = ofputil_pull_phy_port( + static_cast(vconn_get_version(pi->vconn)), pi->reply, pp); + if (!retval) { + return true; + } else if (retval != EOF) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(pi->reply->data, pi->reply->size, + // NULL, NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(pi->reply->data, pi->reply->size, + NULL, verbosity + 1)); + } + } - if (pi->variant == PI_FEATURES || !pi->more) { - return false; - } + if (pi->variant == PI_FEATURES || !pi->more) { + return false; + } - ovs_be32 recv_xid; - do { - ofpbuf_delete(pi->reply); - run(vconn_recv_block(pi->vconn, &pi->reply), "OpenFlow receive failed"); - recv_xid = ((struct ofp_header *)pi->reply->data)->xid; - } while (pi->send_xid != recv_xid); + ovs_be32 recv_xid; + do { + ofpbuf_delete(pi->reply); + run(vconn_recv_block(pi->vconn, &pi->reply), "OpenFlow receive failed"); + recv_xid = ((struct ofp_header *)pi->reply->data)->xid; + } while (pi->send_xid != recv_xid); + + struct ofp_header *oh = (ofp_header *)pi->reply->data; + enum ofptype type; + if (ofptype_pull(&type, pi->reply) || type != OFPTYPE_PORT_DESC_STATS_REPLY) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(pi->reply->data, pi->reply->size, NULL, + // NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(pi->reply->data, pi->reply->size, NULL, + verbosity + 1)); + } - struct ofp_header *oh = (ofp_header *)pi->reply->data; - enum ofptype type; - if (ofptype_pull(&type, pi->reply) || type != OFPTYPE_PORT_DESC_STATS_REPLY) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(pi->reply->data, pi->reply->size, NULL, - // NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(pi->reply->data, pi->reply->size, NULL, NULL, - verbosity + 1)); + pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; } - - pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; - } } /* Destroys iterator 'pi'. */ void OVS_Control::port_iterator_destroy(port_iterator *pi) { - if (pi) { - while (pi->variant == PI_PORT_DESC && pi->more) { - /* Drain vconn's queue of any other replies for this request. */ - struct ofputil_phy_port pp; - port_iterator_next(pi, &pp); - } + if (pi) { + while (pi->variant == PI_PORT_DESC && pi->more) { + /* Drain vconn's queue of any other replies for this request. */ + struct ofputil_phy_port pp; + port_iterator_next(pi, &pp); + } - ofpbuf_delete(pi->reply); - } + ofpbuf_delete(pi->reply); + } } /* Opens a connection to 'vconn_name', fetches the port structure for @@ -1391,33 +1398,33 @@ void OVS_Control::port_iterator_destroy(port_iterator *pi) void OVS_Control::fetch_ofputil_phy_port(const char *vconn_name, const char *port_name, ofputil_phy_port *pp) { - struct vconn *vconn; - ofp_port_t port_no; - bool found = false; + struct vconn *vconn; + ofp_port_t port_no; + bool found = false; - /* Try to interpret the argument as a port number. */ - if (!str_to_ofp(port_name, &port_no)) { - port_no = OFPP_NONE; - } + /* Try to interpret the argument as a port number. */ + if (!str_to_ofp(port_name, &port_no)) { + port_no = OFPP_NONE; + } - /* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the + /* OpenFlow 1.0, 1.1, and 1.2 put the list of ports in the * OFPT_FEATURES_REPLY message. OpenFlow 1.3 and later versions put it * into the OFPST_PORT_DESC reply. Try it the correct way. */ - open_vconn(vconn_name, &vconn); - struct port_iterator pi; - for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp);) { - if (port_no != OFPP_NONE ? port_no == pp->port_no : !strcmp(pp->name, port_name)) { - found = true; - break; + open_vconn(vconn_name, &vconn); + struct port_iterator pi; + for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, pp);) { + if (port_no != OFPP_NONE ? port_no == pp->port_no : !strcmp(pp->name, port_name)) { + found = true; + break; + } } - } - port_iterator_destroy(&pi); - vconn_close(vconn); + port_iterator_destroy(&pi); + vconn_close(vconn); - if (!found) { - // ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name); - ACA_LOG_ERROR("%s: couldn't find port `%s'", vconn_name, port_name); - } + if (!found) { + // ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name); + ACA_LOG_ERROR("%s: couldn't find port `%s'", vconn_name, port_name); + } } /* Initializes 'ti' to prepare for iterating through all of the tables on the @@ -1428,127 +1435,130 @@ void OVS_Control::fetch_ofputil_phy_port(const char *vconn_name, * iterator and thus some tables may be missed or a hang can occur. */ void OVS_Control::table_iterator_init(table_iterator *ti, vconn *vconn) { - memset(ti, 0, sizeof *ti); - ti->vconn = vconn; - ti->variant = (vconn_get_version(vconn) < OFP13_VERSION ? TI_STATS : TI_FEATURES); - ti->more = true; - - enum ofpraw ofpraw = (ti->variant == TI_STATS ? OFPRAW_OFPST_TABLE_REQUEST : - OFPRAW_OFPST13_TABLE_FEATURES_REQUEST); - struct ofpbuf *rq = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0); - ti->send_xid = ((struct ofp_header *)rq->data)->xid; - send_openflow_buffer(ti->vconn, rq); + memset(ti, 0, sizeof *ti); + ti->vconn = vconn; + ti->variant = (vconn_get_version(vconn) < OFP13_VERSION ? TI_STATS : TI_FEATURES); + ti->more = true; + + enum ofpraw ofpraw = (ti->variant == TI_STATS ? OFPRAW_OFPST_TABLE_REQUEST : + OFPRAW_OFPST13_TABLE_FEATURES_REQUEST); + struct ofpbuf *rq = ofpraw_alloc(ofpraw, vconn_get_version(vconn), 0); + ti->send_xid = ((struct ofp_header *)rq->data)->xid; + send_openflow_buffer(ti->vconn, rq); } /* Obtains the next table from 'ti'. On success, returns the next table's * features; on failure, returns NULL. */ const ofputil_table_features *OVS_Control::table_iterator_next(table_iterator *ti) { - for (;;) { - if (ti->reply) { - int retval; - if (ti->variant == TI_STATS) { - struct ofputil_table_stats ts; - retval = ofputil_decode_table_stats_reply(ti->reply, &ts, &ti->features); - } else { - ovs_assert(ti->variant == TI_FEATURES); - retval = ofputil_decode_table_features(ti->reply, &ti->features, &ti->raw_properties); - } - if (!retval) { - return &ti->features; - } else if (retval != EOF) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(ti->reply->data, ti->reply->size, - // NULL, NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(ti->reply->data, ti->reply->size, NULL, - NULL, verbosity + 1)); - } - } + for (;;) { + if (ti->reply) { + int retval; + if (ti->variant == TI_STATS) { + struct ofputil_table_stats ts; + retval = ofputil_decode_table_stats_reply(ti->reply, &ts, &ti->features); + } else { + ovs_assert(ti->variant == TI_FEATURES); + retval = ofputil_decode_table_features(ti->reply, &ti->features, + &ti->raw_properties); + } + if (!retval) { + return &ti->features; + } else if (retval != EOF) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(ti->reply->data, ti->reply->size, + // NULL, NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(ti->reply->data, ti->reply->size, + NULL, verbosity + 1)); + } + } - if (!ti->more) { - return NULL; - } + if (!ti->more) { + return NULL; + } - ovs_be32 recv_xid; - do { - ofpbuf_delete(ti->reply); - run(vconn_recv_block(ti->vconn, &ti->reply), "OpenFlow receive failed"); - recv_xid = ((struct ofp_header *)ti->reply->data)->xid; - } while (ti->send_xid != recv_xid); + ovs_be32 recv_xid; + do { + ofpbuf_delete(ti->reply); + run(vconn_recv_block(ti->vconn, &ti->reply), "OpenFlow receive failed"); + recv_xid = ((struct ofp_header *)ti->reply->data)->xid; + } while (ti->send_xid != recv_xid); + + struct ofp_header *oh = (ofp_header *)ti->reply->data; + enum ofptype type; + if (ofptype_pull(&type, ti->reply) || + type != (ti->variant == TI_STATS ? OFPTYPE_TABLE_STATS_REPLY : + OFPTYPE_TABLE_FEATURES_STATS_REPLY)) { + // ovs_fatal(0, "received bad reply: %s", + // ofp_to_string(ti->reply->data, ti->reply->size, NULL, + // NULL, verbosity + 1)); + ACA_LOG_ERROR("received bad reply: %s", + ofp_to_string(ti->reply->data, ti->reply->size, NULL, + verbosity + 1)); + } - struct ofp_header *oh = (ofp_header *)ti->reply->data; - enum ofptype type; - if (ofptype_pull(&type, ti->reply) || - type != (ti->variant == TI_STATS ? OFPTYPE_TABLE_STATS_REPLY : - OFPTYPE_TABLE_FEATURES_STATS_REPLY)) { - // ovs_fatal(0, "received bad reply: %s", - // ofp_to_string(ti->reply->data, ti->reply->size, NULL, - // NULL, verbosity + 1)); - ACA_LOG_ERROR("received bad reply: %s", - ofp_to_string(ti->reply->data, ti->reply->size, NULL, NULL, - verbosity + 1)); + ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; } - - ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; - } } /* Destroys iterator 'ti'. */ void OVS_Control::table_iterator_destroy(table_iterator *ti) { - if (ti) { - while (ti->more) { - /* Drain vconn's queue of any other replies for this request. */ - table_iterator_next(ti); - } + if (ti) { + while (ti->more) { + /* Drain vconn's queue of any other replies for this request. */ + table_iterator_next(ti); + } - ofpbuf_delete(ti->reply); - } + ofpbuf_delete(ti->reply); + } } const ofputil_port_map *OVS_Control::get_port_map(const char *vconn_name) { - static shash port_maps = SHASH_INITIALIZER(&port_maps); - struct ofputil_port_map *map = (ofputil_port_map *)shash_find_data(&port_maps, vconn_name); - if (!map) { - map = (ofputil_port_map *)malloc(sizeof *map); - ofputil_port_map_init(map); - shash_add(&port_maps, vconn_name, map); - if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { - /* For an active vconn (which includes a vconn constructed from a + static shash port_maps = SHASH_INITIALIZER(&port_maps); + struct ofputil_port_map *map = + (ofputil_port_map *)shash_find_data(&port_maps, vconn_name); + if (!map) { + map = (ofputil_port_map *)malloc(sizeof *map); + ofputil_port_map_init(map); + shash_add(&port_maps, vconn_name, map); + if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { + /* For an active vconn (which includes a vconn constructed from a * bridge name), connect to it and pull down the port name-number * mapping. */ - struct vconn *vconn; - open_vconn(vconn_name, &vconn); + struct vconn *vconn; + open_vconn(vconn_name, &vconn); - struct port_iterator pi; - struct ofputil_phy_port pp; - for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp);) { - ofputil_port_map_put(map, pp.port_no, pp.name); - } - port_iterator_destroy(&pi); + struct port_iterator pi; + struct ofputil_phy_port pp; + for (port_iterator_init(&pi, vconn); port_iterator_next(&pi, &pp);) { + ofputil_port_map_put(map, pp.port_no, pp.name); + } + port_iterator_destroy(&pi); - vconn_close(vconn); - } else { - /* Don't bother with passive vconns, since it could take a long + vconn_close(vconn); + } else { + /* Don't bother with passive vconns, since it could take a long * time for the remote to try to connect to us. Don't bother with * invalid vconn names either. */ + } } - } - return map; + return map; } const ofputil_port_map *OVS_Control::ports_to_accept(const char *vconn_name) { - return should_accept_names() ? get_port_map(vconn_name) : NULL; + return should_accept_names() ? get_port_map(vconn_name) : NULL; } const ofputil_port_map *OVS_Control::ports_to_show(const char *vconn_name) { - return should_show_names() ? get_port_map(vconn_name) : NULL; + return should_show_names() ? get_port_map(vconn_name) : NULL; } +/* const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) { static shash table_maps = SHASH_INITIALIZER(&table_maps); @@ -1559,9 +1569,9 @@ const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) shash_add(&table_maps, vconn_name, map); if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { - /* For an active vconn (which includes a vconn constructed from a - * bridge name), connect to it and pull down the port name-number - * mapping. */ + // For an active vconn (which includes a vconn constructed from a + // * bridge name), connect to it and pull down the port name-number + // * mapping. struct vconn *vconn; open_vconn(vconn_name, &vconn); @@ -1580,9 +1590,9 @@ const ofputil_table_map *OVS_Control::get_table_map(const char *vconn_name) vconn_close(vconn); } else { - /* Don't bother with passive vconns, since it could take a long - * time for the remote to try to connect to us. Don't bother with - * invalid vconn names either. */ + // Don't bother with passive vconns, since it could take a long + // * time for the remote to try to connect to us. Don't bother with + // * invalid vconn names either. } } return map; @@ -1597,23 +1607,24 @@ const ofputil_table_map *OVS_Control::tables_to_show(const char *vconn_name) { return should_show_names() ? get_table_map(vconn_name) : NULL; } +*/ /* We accept port and table names unless the feature is turned off explicitly. */ bool OVS_Control::should_accept_names(void) { - return use_names != 0; + return use_names != 0; } /* We show port and table names only if the feature is turned on explicitly, or * if we're interacting with a user on the console. */ bool OVS_Control::should_show_names(void) { - static int interactive = -1; - if (interactive == -1) { - interactive = isatty(STDOUT_FILENO); - } + static int interactive = -1; + if (interactive == -1) { + interactive = isatty(STDOUT_FILENO); + } - return use_names > 0 || (use_names == -1 && interactive); + return use_names > 0 || (use_names == -1 && interactive); } } // namespace ovs_control diff --git a/src/proto3/CMakeLists.txt b/src/proto3/CMakeLists.txt index c5e41f20..e72e0b7a 100644 --- a/src/proto3/CMakeLists.txt +++ b/src/proto3/CMakeLists.txt @@ -3,4 +3,4 @@ FIND_PACKAGE(Protobuf REQUIRED) INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/../../alcor/schema/proto3/*.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) -ADD_LIBRARY(proto ${ProtoHeaders} ${ProtoSources}) +ADD_LIBRARY(proto ${ProtoHeaders} ${ProtoSources}) \ No newline at end of file diff --git a/src/zeta/aca_zeta_oam_server.cpp b/src/zeta/aca_zeta_oam_server.cpp index 25a2b123..424784ec 100644 --- a/src/zeta/aca_zeta_oam_server.cpp +++ b/src/zeta/aca_zeta_oam_server.cpp @@ -18,15 +18,20 @@ #include #include #include -#include "aca_ovs_l2_programmer.h" #include "aca_util.h" -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_zeta_programming.h" #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_l2_programmer.h" +//#include "aca_ovs_control.h" + using namespace std; -using namespace aca_ovs_control; +//using namespace aca_ovs_control; namespace aca_zeta_oam_server { @@ -289,16 +294,18 @@ int ACA_Zeta_Oam_Server::_add_direct_path(oam_match match, oam_action action) int ACA_Zeta_Oam_Server::_del_direct_path(oam_match match) { + unsigned long not_care_culminative_time; int overall_rc; string vlan_id = to_string(aca_vlan_manager::ACA_Vlan_Manager::get_instance().get_or_create_vlan_id( match.vni)); - string opt = "table=20,priority=50,ip,nw_proto=" + match.proto + + string opt = "del-flows br-tun \"table=20,priority=50,ip,nw_proto=" + match.proto + ",nw_src=" + match.sip + ",nw_dst=" + match.dip + - ",tp_src=" + match.sport + ",tp_dst=" + match.dport + ",dl_vlan=" + vlan_id; + ",tp_src=" + match.sport + ",tp_dst=" + match.dport + ",dl_vlan=" + vlan_id + "\" --strict"; // delete flow - overall_rc = ACA_OVS_Control::get_instance().del_flows("br-tun", opt.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow_command( + opt, not_care_culminative_time, overall_rc); if (overall_rc == EXIT_SUCCESS) { ACA_LOG_INFO("%s", "Delete direct path succeeded!\n"); diff --git a/test/gtest/aca_test_oam.cpp b/test/gtest/aca_test_oam.cpp index a2560c37..ea7d8631 100644 --- a/test/gtest/aca_test_oam.cpp +++ b/test/gtest/aca_test_oam.cpp @@ -18,11 +18,16 @@ #include "aca_zeta_oam_server.h" #include "aca_util.h" #include -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_zeta_programming.h" #include "aca_ovs_l2_programmer.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace aca_zeta_oam_server; using namespace aca_ovs_control; using namespace aca_zeta_programming; diff --git a/test/gtest/aca_test_openflow.cpp b/test/gtest/aca_test_openflow.cpp index d254e3e4..36a18379 100644 --- a/test/gtest/aca_test_openflow.cpp +++ b/test/gtest/aca_test_openflow.cpp @@ -14,14 +14,19 @@ #include "aca_util.h" #include "gtest/gtest.h" -#include "aca_ovs_control.h" -#include "ovs_control.h" +//#include "ovs_control.h" #include "aca_ovs_l2_programmer.h" #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace aca_ovs_control; -using namespace ovs_control; +//using namespace ovs_control; using aca_ovs_l2_programmer::ACA_OVS_L2_Programmer; extern string vmac_address_1; diff --git a/test/gtest/aca_test_ovs_util.cpp b/test/gtest/aca_test_ovs_util.cpp index dcfeb985..1a059674 100644 --- a/test/gtest/aca_test_ovs_util.cpp +++ b/test/gtest/aca_test_ovs_util.cpp @@ -15,7 +15,6 @@ #include "aca_log.h" #include "aca_util.h" #include "aca_config.h" -#include "aca_ovs_control.h" #include "aca_vlan_manager.h" #include "aca_ovs_l2_programmer.h" #include "aca_ovs_l3_programmer.h" @@ -26,6 +25,12 @@ #include #include +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +#include "aca_ovs_control.h" + using namespace std; using namespace alcor::schema; using namespace aca_comm_manager; From cb5f44b31d98c84e1aa90643803bb9a8ca42c360 Mon Sep 17 00:00:00 2001 From: Rio Zhu <32083634+zzxgzgz@users.noreply.github.com> Date: Mon, 13 Sep 2021 17:35:08 -0700 Subject: [PATCH 30/54] Update pulsar to 2.8.0 (#263) --- build/aca-machine-init.sh | 10 +++++++--- build/build.sh | 16 +++++++++++++--- src/aca_main.cpp | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index add7077c..1a7162be 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -199,7 +199,7 @@ echo "6--- installing openvswitch dependancies ---" && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ -PULSAR_RELEASE_TAG='pulsar-2.6.1' +PULSAR_RELEASE_TAG='pulsar-2.8.0' echo "7--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ @@ -210,8 +210,12 @@ echo "7--- installing pulsar dependacies ---" && \ cd ~ echo "8--- building alcor-control-agent" -cd $BUILD/.. && cmake . && make - +cd $BUILD/.. && cmake . && \ +# after cmake ., modify the generated link.txt s so that the "-lssl" and "-lcrypto" appears after the openvswitch, so that it can compile +sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' src/CMakeFiles/AlcorControlAgent.dir/link.txt && \ +sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/aca_tests.dir/link.txt && \ +sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/gs_tests.dir/link.txt && \ +make if [ -n "$1" -a "$1" = "delete-bridges" ]; then echo "9--- deleting br-tun and br-int if requested" PATH=$PATH:/usr/local/share/openvswitch/scripts \ diff --git a/build/build.sh b/build/build.sh index bdfad4a8..c5ef1d69 100755 --- a/build/build.sh +++ b/build/build.sh @@ -32,14 +32,20 @@ docker start a1 if [ "$1" != "test" ]; then # Build alcor control agent echo "--- building alcor-control-agent ---" - docker exec a1 bash -c "cd /mnt/host/code && cmake . && make && \ + docker exec a1 bash -c "cd /mnt/host/code && cmake . && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' src/CMakeFiles/AlcorControlAgent.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/aca_tests.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/gs_tests.dir/link.txt && make && \ /etc/init.d/openvswitch-switch restart && \ ovs-vswitchd --pidfile --detach" else sed -i.bak -E 's/("add-br )([a-z]+-[a-z]+)(")/\1\2 -- set bridge \2 datapath_type=netdev\3/g' $BUILD/../src/ovs/aca_ovs_l2_programmer.cpp # Build alcor control agent echo "--- building alcor-control-agent pre test ---" - docker exec a1 bash -c "cd /mnt/host/code && cmake . && make" + docker exec a1 bash -c "cd /mnt/host/code && cmake . && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' src/CMakeFiles/AlcorControlAgent.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/aca_tests.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/gs_tests.dir/link.txt && make" echo "--- Start ACA Unit test ---" echo " --- rebuilding br-tun and br-int" @@ -73,7 +79,11 @@ else mv -f $BUILD/../src/ovs/aca_ovs_l2_programmer.cpp.bak $BUILD/../src/ovs/aca_ovs_l2_programmer.cpp # Build alcor control agent echo "--- building alcor-control-agent post test ---" - docker exec a1 bash -c "cd /mnt/host/code && make" + docker exec a1 bash -c "cd /mnt/host/code && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' src/CMakeFiles/AlcorControlAgent.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/aca_tests.dir/link.txt && \ + sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/gs_tests.dir/link.txt && \ + make" fi diff --git a/src/aca_main.cpp b/src/aca_main.cpp index e599dc4a..30e338ac 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -287,8 +287,8 @@ int main(int argc, char *argv[]) //// monitor br-tun for arp request message //ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); - //ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); - //rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); + rc = network_config_consumer.consumeDispatched(g_pulsar_topic); pause(); aca_cleanup(); From 57682ee3bd061eae930ff81018ce3387ea9eec7a Mon Sep 17 00:00:00 2001 From: Rio Zhu <32083634+zzxgzgz@users.noreply.github.com> Date: Fri, 1 Oct 2021 17:33:56 -0700 Subject: [PATCH 31/54] Batching and parallel resource state processing for million ovs flows (#264) --- include/aca_log.h | 4 +- src/comm/aca_comm_mgr.cpp | 13 +-- src/comm/aca_grpc.cpp | 3 + src/dp_abstraction/aca_dataplane_ovs.cpp | 77 ++-------------- src/dp_abstraction/aca_goal_state_handler.cpp | 90 ++++++++++++++++--- src/ovs/aca_ovs_l2_programmer.cpp | 6 +- src/ovs/aca_ovs_l3_programmer.cpp | 9 +- src/ovs/aca_vlan_manager.cpp | 8 -- 8 files changed, 98 insertions(+), 112 deletions(-) diff --git a/include/aca_log.h b/include/aca_log.h index 187bb544..dde121a9 100644 --- a/include/aca_log.h +++ b/include/aca_log.h @@ -35,9 +35,9 @@ extern bool g_debug_mode; /* debug-level message */ #define ACA_LOG_DEBUG(f_, ...) \ do { \ - syslog(LOG_DEBUG, "[%s:%d] " f_, __func__, __LINE__, \ - ##__VA_ARGS__); \ if (g_debug_mode) { \ + syslog(LOG_DEBUG, "[%s:%d] " f_, __func__, __LINE__, \ + ##__VA_ARGS__); \ fprintf(stdout, f_, ##__VA_ARGS__); \ } \ } while (0) diff --git a/src/comm/aca_comm_mgr.cpp b/src/comm/aca_comm_mgr.cpp index dd6e12d9..8c36fabf 100644 --- a/src/comm/aca_comm_mgr.cpp +++ b/src/comm/aca_comm_mgr.cpp @@ -143,7 +143,7 @@ int Aca_Comm_Manager::update_goal_state(GoalState &goal_state_message, cast_to_microseconds(end - neighbor_update_finished_time).count(); auto message_total_operation_time = cast_to_microseconds(end - start).count(); - ACA_LOG_DEBUG("[METRICS] Elapsed time for message total operation took: %ld microseconds or %ld milliseconds\n\ + ACA_LOG_INFO("[METRICS] Elapsed time for message total operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for router operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for port operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for neighbor operation took: %ld microseconds or %ld milliseconds\n\ @@ -168,18 +168,9 @@ int Aca_Comm_Manager::update_goal_state(GoalStateV2 &goal_state_message, int exec_command_rc; int rc = EXIT_SUCCESS; auto start = chrono::steady_clock::now(); - auto t0 = std::chrono::high_resolution_clock::now(); - ACA_LOG_DEBUG("Starting to update goal state with format_version: %u\n", - goal_state_message.format_version()); - - ACA_LOG_DEBUG("[METRICS] Goal state message size is: %lu bytes, router_state_size: [%d]\n", - goal_state_message.ByteSizeLong(), - goal_state_message.router_states_size()); this->print_goal_state(goal_state_message); - auto t1 = std::chrono::high_resolution_clock::now(); - ACA_LOG_DEBUG("[METRICS] Printout took: [%ld] nanoseconds\n", (t1 - t0).count()); auto gs_printout_finished_time = chrono::steady_clock::now(); auto gs_printout_operation_time = cast_to_microseconds(gs_printout_finished_time - start).count(); @@ -243,7 +234,7 @@ int Aca_Comm_Manager::update_goal_state(GoalStateV2 &goal_state_message, cast_to_microseconds(end - neighbor_update_finished_time).count(); auto message_total_operation_time = cast_to_microseconds(end - start).count(); - ACA_LOG_DEBUG("[METRICS] Elapsed time for message total operation took: %ld microseconds or %ld milliseconds\n\ + ACA_LOG_INFO("[METRICS] Elapsed time for message total operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for gs printout operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for router operation took: %ld microseconds or %ld milliseconds\n\ [METRICS] Elapsed time for port operation took: %ld microseconds or %ld milliseconds\n\ diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index c92ff59f..3933f17f 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -285,6 +285,9 @@ void GoalStateProvisionerAsyncServer::RunServer(int thread_pool_size) ServerBuilder builder; string GRPC_SERVER_ADDRESS = "0.0.0.0:" + g_grpc_server_port; builder.AddListeningPort(GRPC_SERVER_ADDRESS, grpc::InsecureServerCredentials()); + builder.SetMaxMessageSize(INT_MAX); + builder.SetMaxReceiveMessageSize(INT_MAX); + builder.SetMaxSendMessageSize(INT_MAX); builder.RegisterService(&service_); cq_ = builder.AddCompletionQueue(); server_ = builder.BuildAndStart(); diff --git a/src/dp_abstraction/aca_dataplane_ovs.cpp b/src/dp_abstraction/aca_dataplane_ovs.cpp index b33b56da..ba27a27b 100644 --- a/src/dp_abstraction/aca_dataplane_ovs.cpp +++ b/src/dp_abstraction/aca_dataplane_ovs.cpp @@ -755,35 +755,19 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig ulong culminative_dataplane_programming_time = 0; ulong culminative_network_configuration_time = 0; - auto operation_start = chrono::high_resolution_clock::now(); - - static std::chrono::_V2::high_resolution_clock::time_point got_neighbor_configuration_time; - static std::chrono::_V2::high_resolution_clock::time_point validate_fixed_ip_size_time; - static std::chrono::_V2::high_resolution_clock::time_point assert_revision_number_time; - static std::chrono::_V2::high_resolution_clock::time_point fixed_ip_loop_start; - static std::chrono::_V2::high_resolution_clock::time_point update_neighbor_time; - static std::chrono::_V2::high_resolution_clock::time_point found_subnet_info_time; - static std::chrono::_V2::high_resolution_clock::time_point determined_same_host_time; - - auto init_time_vars_time = chrono::high_resolution_clock::now(); - alcor::schema::NeighborConfiguration current_NeighborConfiguration = current_NeighborState.configuration(); - got_neighbor_configuration_time = chrono::high_resolution_clock::now(); - try { if (!aca_validate_fixed_ips_size(current_NeighborConfiguration.fixed_ips_size())) { throw std::invalid_argument("NeighborConfiguration.fixed_ips_size is less than zero"); } - validate_fixed_ip_size_time = chrono::high_resolution_clock::now(); + // validate_fixed_ip_size_time = chrono::high_resolution_clock::now(); // TODO: need to design the usage of current_NeighborConfiguration.revision_number() assert(current_NeighborConfiguration.revision_number() > 0); - assert_revision_number_time = chrono::high_resolution_clock::now(); + for (int ip_index = 0; ip_index < current_NeighborConfiguration.fixed_ips_size(); ip_index++) { - ACA_LOG_DEBUG("In fixed ip loop, index: %ld\n", ip_index); - fixed_ip_loop_start = chrono::high_resolution_clock::now(); auto current_fixed_ip = current_NeighborConfiguration.fixed_ips(ip_index); if (current_fixed_ip.neighbor_type() == NeighborType::L2 || @@ -828,7 +812,6 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig subnet_info_found = true; } - found_subnet_info_time = chrono::high_resolution_clock::now(); if (!subnet_info_found) { ACA_LOG_ERROR("Not able to find the info for neighbor ip_index: %d with subnet ID: %s.\n", @@ -852,7 +835,6 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig // only need to update L2 neighbor info if it is not on the same compute host bool is_neighbor_port_on_same_host = ACA_OVS_L2_Programmer::get_instance().is_ip_on_the_same_host(host_ip_address); - determined_same_host_time = chrono::high_resolution_clock::now(); if (is_neighbor_port_on_same_host) { ACA_LOG_DEBUG("neighbor host: %s is on the same compute node, don't need to update L2 neighbor info.\n", @@ -884,12 +866,14 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig if ((current_NeighborState.operation_type() == OperationType::CREATE) || (current_NeighborState.operation_type() == OperationType::UPDATE) || (current_NeighborState.operation_type() == OperationType::INFO)) { + overall_rc = ACA_OVS_L3_Programmer::get_instance().create_or_update_l3_neighbor( current_NeighborConfiguration.id(), current_NeighborConfiguration.vpc_id(), current_fixed_ip.subnet_id(), virtual_ip_address, virtual_mac_address, host_ip_address, found_tunnel_id, culminative_dataplane_programming_time); + } else if (current_NeighborState.operation_type() == OperationType::DELETE) { overall_rc = ACA_OVS_L3_Programmer::get_instance().delete_l3_neighbor( current_NeighborConfiguration.id(), current_fixed_ip.subnet_id(), @@ -902,7 +886,6 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig } } } - update_neighbor_time = chrono::high_resolution_clock::now(); } else { ACA_LOG_ERROR("Unknown neighbor_type: %d.\n", current_NeighborState.operation_type()); @@ -924,62 +907,12 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig overall_rc = -EFAULT; } - auto operation_end = chrono::high_resolution_clock::now(); - - auto operation_total_time = - cast_to_microseconds(operation_end - operation_start).count(); - - auto init_time_vars_total_time = - cast_to_microseconds(init_time_vars_time - operation_start).count(); - - auto get_neighbor_configuration_total_time = - cast_to_microseconds(got_neighbor_configuration_time - init_time_vars_time) - .count(); - - auto check_fixed_ip_size_total_time = - cast_to_microseconds(validate_fixed_ip_size_time - got_neighbor_configuration_time) - .count(); - - auto assert_revision_number_total_time = - cast_to_microseconds(assert_revision_number_time - validate_fixed_ip_size_time) - .count(); - - auto validate_info_total_time = - cast_to_microseconds(found_subnet_info_time - fixed_ip_loop_start).count(); - - auto determine_same_host_total_time = - cast_to_microseconds(determined_same_host_time - found_subnet_info_time) - .count(); - auto update_neighbor_total_time = - cast_to_microseconds(update_neighbor_time - determined_same_host_time).count(); - aca_goal_state_handler::Aca_Goal_State_Handler::get_instance().add_goal_state_operation_status( - gsOperationReply, current_NeighborConfiguration.id(), - ResourceType::NEIGHBOR, current_NeighborState.operation_type(), - overall_rc, culminative_dataplane_programming_time, - culminative_network_configuration_time, operation_total_time); - if (overall_rc == EXIT_SUCCESS) { ACA_LOG_INFO("%s", "Successfully configured the neighbor state.\n"); } else { ACA_LOG_ERROR("Unable to configure the neighbor state: rc=%d\n", overall_rc); } - ACA_LOG_DEBUG( - "[METRICS] Elapsed time for updating 1 neighbor state, total time is %ld microseconds, or %ld milliseconds\n\ -[METRICS] Elapsed time for initing the time stamps took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for getting neighbor configuration took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for assuring fixed IP size took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for assuring revision number took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for determining same host took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for validate info took %ld microseconds, or %ld milliseconds.\n\ -[METRICS] Elapsed time for updating neighbor info took %ld microseconds, or %ld milliseconds.\n", - operation_total_time, us_to_ms(operation_total_time), init_time_vars_total_time, - us_to_ms(init_time_vars_total_time), get_neighbor_configuration_total_time, - us_to_ms(get_neighbor_configuration_total_time), - check_fixed_ip_size_total_time, us_to_ms(check_fixed_ip_size_total_time), - assert_revision_number_total_time, us_to_ms(assert_revision_number_total_time), - determine_same_host_total_time, us_to_ms(determine_same_host_total_time), - validate_info_total_time, us_to_ms(validate_info_total_time), - update_neighbor_total_time, us_to_ms(update_neighbor_total_time)); + return overall_rc; } diff --git a/src/dp_abstraction/aca_goal_state_handler.cpp b/src/dp_abstraction/aca_goal_state_handler.cpp index 0a6c2d97..81b72351 100644 --- a/src/dp_abstraction/aca_goal_state_handler.cpp +++ b/src/dp_abstraction/aca_goal_state_handler.cpp @@ -21,7 +21,7 @@ using namespace alcor::schema; std::mutex gs_reply_mutex; // mutex for writing gs reply object - +const int resource_state_processing_batch_size = 10000; // batch size of concurrently processing a kind of resource states. namespace aca_goal_state_handler { Aca_Goal_State_Handler::Aca_Goal_State_Handler() @@ -139,6 +139,7 @@ int Aca_Goal_State_Handler::update_port_states(GoalState &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; + int count = 1; for (int i = 0; i < parsed_struct.port_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing port states #%d\n", i); @@ -148,14 +149,24 @@ int Aca_Goal_State_Handler::update_port_states(GoalState &parsed_struct, workitem_future.push_back(std::async( std::launch::async, &Aca_Goal_State_Handler::update_port_state_workitem, this, current_PortState, std::ref(parsed_struct), std::ref(gsOperationReply))); - + if (count % resource_state_processing_batch_size == 0){ + for (int i = 0; i < workitem_future.size(); i++) { + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS) + overall_rc = rc; + } + workitem_future.clear(); + count = 1; + } else { + count ++; + } // keeping below just in case if we want to call it serially // rc = update_port_state_workitem(current_PortState, parsed_struct, gsOperationReply); // if (rc != EXIT_SUCCESS) // overall_rc = rc; } // for (int i = 0; i < parsed_struct.port_states_size(); i++) - for (int i = 0; i < parsed_struct.port_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; @@ -180,7 +191,7 @@ int Aca_Goal_State_Handler::update_port_states(GoalStateV2 &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; - + int count = 1; // below is a c++ 17 feature for (auto &[port_id, current_PortState] : parsed_struct.port_states()) { ACA_LOG_DEBUG("=====>parsing port state: %s\n", port_id.c_str()); @@ -188,14 +199,24 @@ int Aca_Goal_State_Handler::update_port_states(GoalStateV2 &parsed_struct, workitem_future.push_back(std::async( std::launch::async, &Aca_Goal_State_Handler::update_port_state_workitem_v2, this, current_PortState, std::ref(parsed_struct), std::ref(gsOperationReply))); - + if (count % resource_state_processing_batch_size == 0) { + for (int i = 0; i < workitem_future.size(); i++) { + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS) + overall_rc = rc; + } + workitem_future.clear(); + count = 1; + } else { + count ++; + } // keeping below just in case if we want to call it serially // rc = update_port_state_workitem(current_PortState, parsed_struct, gsOperationReply); // if (rc != EXIT_SUCCESS) // overall_rc = rc; } // for (int i = 0; i < parsed_struct.port_states_size(); i++) - for (int i = 0; i < parsed_struct.port_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; @@ -218,6 +239,7 @@ int Aca_Goal_State_Handler::update_neighbor_states(GoalState &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; + int count = 1; for (int i = 0; i < parsed_struct.neighbor_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing neighbor states #%d\n", i); @@ -228,9 +250,20 @@ int Aca_Goal_State_Handler::update_neighbor_states(GoalState &parsed_struct, std::launch::async, &Aca_Goal_State_Handler::update_neighbor_state_workitem, this, current_NeighborState, std::ref(parsed_struct), std::ref(gsOperationReply))); + if (count % resource_state_processing_batch_size == 0) { + for (int i = 0; i < workitem_future.size(); i++) { + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS) + overall_rc = rc; + } + workitem_future.clear(); + count = 1; + } else { + count ++; + } } - for (int i = 0; i < parsed_struct.neighbor_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; @@ -253,6 +286,7 @@ int Aca_Goal_State_Handler::update_router_states(GoalState &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; + int count = 1; for (int i = 0; i < parsed_struct.router_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing router states #%d\n", i); @@ -262,9 +296,20 @@ int Aca_Goal_State_Handler::update_router_states(GoalState &parsed_struct, workitem_future.push_back(std::async( std::launch::async, &Aca_Goal_State_Handler::update_router_state_workitem, this, current_RouterState, std::ref(parsed_struct), std::ref(gsOperationReply))); + if (count % resource_state_processing_batch_size == 0) { + for (int i = 0; i < workitem_future.size(); i++) { + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS) + overall_rc = rc; + } + workitem_future.clear(); + count = 1; + } else { + count ++; + } } - for (int i = 0; i < parsed_struct.router_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; @@ -287,6 +332,7 @@ int Aca_Goal_State_Handler::update_neighbor_states(GoalStateV2 &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; + int count = 1; for (auto &[neighbor_id, current_NeighborState] : parsed_struct.neighbor_states()) { ACA_LOG_DEBUG("=====>parsing neighbor state: %s\n", neighbor_id.c_str()); @@ -295,9 +341,21 @@ int Aca_Goal_State_Handler::update_neighbor_states(GoalStateV2 &parsed_struct, std::launch::async, &Aca_Goal_State_Handler::update_neighbor_state_workitem_v2, this, current_NeighborState, std::ref(parsed_struct), std::ref(gsOperationReply))); + if (count % resource_state_processing_batch_size == 0) { + for (int i = 0 ; i < workitem_future.size(); i++){ + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS){ + overall_rc = rc; + } + } + workitem_future.clear(); + count = 1; + } else { + count++; + } } - for (int i = 0; i < parsed_struct.neighbor_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; @@ -320,6 +378,7 @@ int Aca_Goal_State_Handler::update_router_states(GoalStateV2 &parsed_struct, std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; + int count = 1; for (auto &[router_id, current_RouterState] : parsed_struct.router_states()) { ACA_LOG_DEBUG("=====>parsing router state: %s\n", router_id.c_str()); @@ -327,9 +386,20 @@ int Aca_Goal_State_Handler::update_router_states(GoalStateV2 &parsed_struct, workitem_future.push_back(std::async( std::launch::async, &Aca_Goal_State_Handler::update_router_state_workitem_v2, this, current_RouterState, std::ref(parsed_struct), std::ref(gsOperationReply))); + if (count % resource_state_processing_batch_size == 0){ + for (int i = 0; i < workitem_future.size(); i++) { + rc = workitem_future[i].get(); + if (rc != EXIT_SUCCESS) + overall_rc = rc; + } + workitem_future.clear(); + count = 1; + } else { + count ++; + } } - for (int i = 0; i < parsed_struct.router_states_size(); i++) { + for (int i = 0; i < workitem_future.size(); i++) { rc = workitem_future[i].get(); if (rc != EXIT_SUCCESS) overall_rc = rc; diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index f3d0ec01..f9bbb6cf 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -657,9 +657,9 @@ void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, g_total_execute_openflow_time += openflow_client_time_total_time; - ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", - openflow_client_time_total_time, - us_to_ms(openflow_client_time_total_time)); + // ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + // openflow_client_time_total_time, + // us_to_ms(openflow_client_time_total_time)); ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Exiting\n"); } diff --git a/src/ovs/aca_ovs_l3_programmer.cpp b/src/ovs/aca_ovs_l3_programmer.cpp index 8912fa8e..5d7b37af 100644 --- a/src/ovs/aca_ovs_l3_programmer.cpp +++ b/src/ovs/aca_ovs_l3_programmer.cpp @@ -455,7 +455,7 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ if (!is_router_exist || (current_RouterConfiguration.update_type() == UpdateType::FULL)) { // -----critical section starts----- _routers_table_mutex.lock(); - _routers_table.emplace(router_id, new_subnet_routing_tables); + _routers_table[router_id] = new_subnet_routing_tables; _routers_table_mutex.unlock(); // -----critical section ends----- ACA_LOG_INFO("Added router entry for router id %s\n", router_id.c_str()); @@ -880,7 +880,7 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ if (!is_router_exist || (current_RouterConfiguration.update_type() == UpdateType::FULL)) { // -----critical section starts----- _routers_table_mutex.lock(); - _routers_table.emplace(router_id, new_subnet_routing_tables); + _routers_table[router_id] = new_subnet_routing_tables; _routers_table_mutex.unlock(); // -----critical section ends----- ACA_LOG_INFO("Added router entry for router id %s\n", router_id.c_str()); @@ -962,10 +962,7 @@ int ACA_OVS_L3_Programmer::create_or_update_l3_neighbor( ACA_LOG_DEBUG("router ID:%s\n ", router_it->first.c_str()); // try to see if the destination subnet GW is connected to the current router auto found_subnet = router_it->second.find(subnet_id); - for (auto kv : router_it->second) { - ACA_LOG_DEBUG("[create_or_update_l3_neighbor] router ID: [%s], subnet routering table's subnet ID: [%s], subnet_id we're looking for: [%s]\n", - router_it->first.c_str(), kv.first.c_str(), subnet_id.c_str()); - } + if (found_subnet == router_it->second.end()) { // subnet not found in this router, go look at the next router continue; diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index 99721f75..16b791af 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -197,18 +197,10 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, "->NXM_NX_TUN_ID[],set_field:" + remote_host_ip + "->tun_dst,output:" + VXLAN_GENERIC_OUTPORT_NUMBER; - std::chrono::_V2::steady_clock::time_point start = std::chrono::steady_clock::now(); aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, "br-tun", match_string + action_string, "add"); - std::chrono::_V2::steady_clock::time_point end = std::chrono::steady_clock::now(); - - auto message_total_operation_time = - std::chrono::duration_cast(end - start).count(); - ACA_LOG_DEBUG("[create_l2_neighbor] Start adding ovs rule at: [%ld], finished at: [%ld]\nElapsed time for adding ovs rule for l2 neighbor took: %ld microseconds or %ld milliseconds\n", - start, end, message_total_operation_time, - (message_total_operation_time / 1000)); // create arp entry in arp responder for the l2 neighbor stArpCfg.mac_address = virtual_mac; From 35ccab3d38d29fda5b846ef2ea4e03f474fd38bb Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Wed, 20 Oct 2021 21:25:53 +0000 Subject: [PATCH 32/54] Changed implementation for adding/removing switches from maps, in order to prevent deadlock --- include/of_controller.h | 2 ++ src/ovs/of_controller.cpp | 51 ++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/include/of_controller.h b/include/of_controller.h index 21147d70..3e91bc77 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -75,6 +75,8 @@ class OFController : public OFServer { void remove_switch_from_conn_map(int ofconn_id); + void remove_switch_from_conn_maps(std::string bridge, int ofconn_id); + void setup_default_br_int_flows(); void setup_default_br_tun_flows(); diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index e7f9a079..7796c526 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -98,13 +98,15 @@ void OFController::connection_callback(OFConnection* ofconn, OFConnection::Event } else if (type == OFConnection::EVENT_CLOSED) { std::string bridge = switch_id_map[ofconn->get_id()]; ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed by user, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); - remove_switch_from_conn_map(ofconn->get_id()); - remove_switch_from_conn_map(bridge); + remove_switch_from_conn_maps(bridge, ofconn->get_id()); + // remove_switch_from_conn_map(ofconn->get_id()); + // remove_switch_from_conn_map(bridge); } else if (type == OFConnection::EVENT_DEAD) { std::string bridge = switch_id_map[ofconn->get_id()]; ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed due to inactivity, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); - remove_switch_from_conn_map(ofconn->get_id()); - remove_switch_from_conn_map(bridge); + remove_switch_from_conn_maps(bridge, ofconn->get_id()); + // remove_switch_from_conn_map(ofconn->get_id()); + // remove_switch_from_conn_map(bridge); } } @@ -124,16 +126,22 @@ OFConnection* OFController::get_instance(std::string bridge) { void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn) { switch_map_mutex.lock(); - if (switch_conn_map.find(bridge) != switch_conn_map.end()) { - // if existing already, remove then insert to update - remove_switch_from_conn_map(bridge); + auto ofconn_iter = switch_conn_map.find(bridge); + + // if found, remove + if (ofconn_iter != switch_conn_map.end()) { + if (NULL != ofconn_iter->second) { // k is bridge name, v is OFConnection* + ofconn_iter->second->close(); + } + switch_conn_map.erase(bridge); } + switch_conn_map[bridge] = ofconn; if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { - // if existing already, remove then insert to update - remove_switch_from_conn_map(ofconn_id); + switch_id_map.erase(ofconn_id); } + switch_id_map[ofconn_id] = bridge; switch_map_mutex.unlock(); @@ -141,6 +149,31 @@ void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFC ofconn->get_id(), bridge.c_str()); } +void OFController::remove_switch_from_conn_maps(std::string bridge, int ofconn_id){ + switch_map_mutex.lock(); + + // if found, remove + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { + switch_id_map.erase(ofconn_id); + } + + auto ofconn_iter = switch_conn_map.find(bridge); + + // if found, remove + if (ofconn_iter != switch_conn_map.end()) { + if (NULL != ofconn_iter->second) { // k is bridge name, v is OFConnection* + ofconn_iter->second->close(); + } + switch_conn_map.erase(bridge); + } + + switch_map_mutex.unlock(); + + ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection bridge=%s removed from switch map\n", + bridge.c_str()); +} + + void OFController::remove_switch_from_conn_map(std::string bridge) { switch_map_mutex.lock(); auto ofconn_iter = switch_conn_map.find(bridge); From e08d47b92f4c33fcbed21453f8ec027ba97ce322 Mon Sep 17 00:00:00 2001 From: Rio Zhu <32083634+zzxgzgz@users.noreply.github.com> Date: Wed, 27 Oct 2021 17:57:04 -0700 Subject: [PATCH 33/54] Changed to use of controller to delete l2 neighbor (#270) --- src/ovs/aca_vlan_manager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ovs/aca_vlan_manager.cpp b/src/ovs/aca_vlan_manager.cpp index 16b791af..91318c69 100644 --- a/src/ovs/aca_vlan_manager.cpp +++ b/src/ovs/aca_vlan_manager.cpp @@ -219,11 +219,11 @@ int ACA_Vlan_Manager::create_l2_neighbor(string virtual_ip, string virtual_mac, // called when a L2 neighbor is deleted int ACA_Vlan_Manager::delete_l2_neighbor(string virtual_ip, string virtual_mac, - uint tunnel_id, ulong & /*culminative_time*/) + uint tunnel_id, ulong & culminative_time) { ACA_LOG_DEBUG("%s", "ACA_Vlan_Manager::delete_l2_neighbor ---> Entering\n"); - int rc; + int rc = EXIT_SUCCESS; int overall_rc = EXIT_SUCCESS; int internal_vlan_id = get_or_create_vlan_id(tunnel_id); @@ -234,7 +234,10 @@ int ACA_Vlan_Manager::delete_l2_neighbor(string virtual_ip, string virtual_mac, string match_string = "table=20,priority=50,dl_vlan=" + to_string(internal_vlan_id) + ",dl_dst:" + virtual_mac; - rc = ACA_OVS_Control::get_instance().del_flows("br-tun", match_string.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_time, + "br-tun", + match_string, + "del"); if (rc != EXIT_SUCCESS) { ACA_LOG_ERROR("Failed to delete L2 neighbor rule, rc: %d\n", rc); From 0a2f0b6c74ba6a21ebc0e382fb5ec920762c93ea Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Thu, 28 Oct 2021 20:34:41 +0000 Subject: [PATCH 34/54] Removed commented code, also added comments for OFController::add_switch_to_conn_map and OFController::remove_switch_from_conn_maps --- src/ovs/of_controller.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index 7796c526..b1ad302b 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -99,14 +99,10 @@ void OFController::connection_callback(OFConnection* ofconn, OFConnection::Event std::string bridge = switch_id_map[ofconn->get_id()]; ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed by user, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); remove_switch_from_conn_maps(bridge, ofconn->get_id()); - // remove_switch_from_conn_map(ofconn->get_id()); - // remove_switch_from_conn_map(bridge); } else if (type == OFConnection::EVENT_DEAD) { std::string bridge = switch_id_map[ofconn->get_id()]; ACA_LOG_WARN("OFController::connection_callback - ovs connection id=%d closed due to inactivity, remove %s from switch map\n", ofconn->get_id(), bridge.c_str()); remove_switch_from_conn_maps(bridge, ofconn->get_id()); - // remove_switch_from_conn_map(ofconn->get_id()); - // remove_switch_from_conn_map(bridge); } } @@ -124,6 +120,8 @@ OFConnection* OFController::get_instance(std::string bridge) { return ofconn; } +// Adding a connection should be an atomic action, meaning that both adding to +// switch_con_map and switch_id_map should be added under the same lock void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFConnection* ofconn) { switch_map_mutex.lock(); auto ofconn_iter = switch_conn_map.find(bridge); @@ -149,6 +147,8 @@ void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFC ofconn->get_id(), bridge.c_str()); } +// Removing a connection should be an atomic action, meaning that both removing from +// switch_con_map and switch_id_map should be added under the same lock void OFController::remove_switch_from_conn_maps(std::string bridge, int ofconn_id){ switch_map_mutex.lock(); From 02e05c48a59d0761a9bf2db217e6156e29b9c583 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 01:08:38 +0000 Subject: [PATCH 35/54] Tried to let client know a call is finished --- src/comm/aca_grpc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 3933f17f..3ba6cc59 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -220,6 +220,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); + streamingCall->stream_.Finish(grpc::Status::OK, baseCall); break; default: break; From 717bbf681980958ed2ab65d78b9cdec9d0304f8e Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 01:20:27 +0000 Subject: [PATCH 36/54] Tried to let client know a call is finished --- src/comm/aca_grpc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 3ba6cc59..1227f79e 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -220,7 +220,8 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); - streamingCall->stream_.Finish(grpc::Status::OK, baseCall); + streamingCall->stream_.Finish(Status::OK, baseCall); + delete streamingCall; break; default: break; From 15080296aa8543f94520050a790a1de84ebd007e Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 01:29:39 +0000 Subject: [PATCH 37/54] Tried to let client know a call is finished --- src/comm/aca_grpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 1227f79e..d2a2da07 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -220,7 +220,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); - streamingCall->stream_.Finish(Status::OK, baseCall); + streamingCall->stream_.Finish(Status::OK, static_cast(baseCall)); delete streamingCall; break; default: From d2fd95531e0bad63c6786b7203de78d4a1deda23 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 18:11:34 +0000 Subject: [PATCH 38/54] Suspect if it is the gsoperationreply.clear() that causes the crash --- src/comm/aca_grpc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index d2a2da07..3c2b4c9c 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -214,14 +214,14 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( streamingCall->status_ = AsyncGoalStateProvionerCallBase::CallStatus::SENT; streamingCall->hasReadFromStream = false; streamingCall->stream_.Write(streamingCall->gsOperationReply_, baseCall); - streamingCall->gsOperationReply_.Clear(); + // streamingCall->gsOperationReply_.Clear(); } } break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); - streamingCall->stream_.Finish(Status::OK, static_cast(baseCall)); - delete streamingCall; + streamingCall->stream_.Finish(Status::OK, baseCall); + delete baseCall; break; default: break; From 15c46da203266b226ea6bf99894588a10f622d1a Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 18:21:47 +0000 Subject: [PATCH 39/54] Try to clear a reply right before it is FINISHed --- src/comm/aca_grpc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 3c2b4c9c..ee564ff8 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -221,6 +221,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); + streamingCall->gsOperationReply_.Clear(); delete baseCall; break; default: From cfae06e28caec16f00b333db7f4707af87a43e3f Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 18:26:22 +0000 Subject: [PATCH 40/54] Maybe shouldn't clear the reply, probably doesn't have to, too --- src/comm/aca_grpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index ee564ff8..c65be886 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -214,6 +214,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( streamingCall->status_ = AsyncGoalStateProvionerCallBase::CallStatus::SENT; streamingCall->hasReadFromStream = false; streamingCall->stream_.Write(streamingCall->gsOperationReply_, baseCall); + // this call will make ACA crash if we need to call the stream.Finish // streamingCall->gsOperationReply_.Clear(); } } @@ -221,7 +222,6 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); - streamingCall->gsOperationReply_.Clear(); delete baseCall; break; default: From 9bbe195a2bf147af719a1ad4fb5a1e167f50fbdc Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 18:42:02 +0000 Subject: [PATCH 41/54] Still crashing --- src/comm/aca_grpc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index c65be886..6d8fe95a 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -214,14 +214,13 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( streamingCall->status_ = AsyncGoalStateProvionerCallBase::CallStatus::SENT; streamingCall->hasReadFromStream = false; streamingCall->stream_.Write(streamingCall->gsOperationReply_, baseCall); - // this call will make ACA crash if we need to call the stream.Finish - // streamingCall->gsOperationReply_.Clear(); } } break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); + streamingCall->gsOperationReply_.Clear(); delete baseCall; break; default: From 22d15fe3ff1ecaccb96f70f07cce3ca629f8a3c6 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 19:12:49 +0000 Subject: [PATCH 42/54] Try to not delete the call object --- src/comm/aca_grpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 6d8fe95a..798f2f3c 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -221,7 +221,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); streamingCall->gsOperationReply_.Clear(); - delete baseCall; +// delete baseCall; break; default: break; From 861b930019d1ed225414346550c8864d2dda2246 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 19:38:35 +0000 Subject: [PATCH 43/54] Try to delete call object separately --- src/comm/aca_grpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 798f2f3c..83f6039b 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -221,9 +221,9 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); streamingCall->gsOperationReply_.Clear(); -// delete baseCall; break; default: + delete baseCall; break; } } From f1bd3f3bd81244fe9f070aaa4cdd76c9b28126f6 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 19:41:10 +0000 Subject: [PATCH 44/54] Try to delete call object separately --- src/comm/aca_grpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 83f6039b..87536d05 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -220,7 +220,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); streamingCall->stream_.Finish(Status::OK, baseCall); - streamingCall->gsOperationReply_.Clear(); +// streamingCall->gsOperationReply_.Clear(); break; default: delete baseCall; From e734418b982795ddb3a2d98d0f99fe869f07a613 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 19:45:11 +0000 Subject: [PATCH 45/54] Added logs in DEFAULT state --- src/comm/aca_grpc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 87536d05..e736159f 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -223,6 +223,7 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( // streamingCall->gsOperationReply_.Clear(); break; default: + ACA_LOG_DEBUG("%s\n", "PushGoalStatesStream call in at DEFAULT state"); delete baseCall; break; } From a023cb4e378d2239795d6fc3e3898187c5b260d2 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 20:03:00 +0000 Subject: [PATCH 46/54] Added more logs --- src/comm/aca_grpc.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index e736159f..06f87e4c 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -218,13 +218,15 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( } break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: - ACA_LOG_DEBUG("%s\n", "Nothing to do when a PushGoalStatesStream call in at SENT state"); + ACA_LOG_DEBUG("%s\n", "In SENT state, calling .Finish"); streamingCall->stream_.Finish(Status::OK, baseCall); -// streamingCall->gsOperationReply_.Clear(); + ACA_LOG_DEBUG("%s\n", "In SENT state, calling gsOperationReply_.Clear()"); + streamingCall->gsOperationReply_.Clear(); + ACA_LOG_DEBUG("%s\n", "In SENT state, calling delete baseCall"); + delete (PushGoalStatesStreamAsyncCall *)baseCall; break; default: ACA_LOG_DEBUG("%s\n", "PushGoalStatesStream call in at DEFAULT state"); - delete baseCall; break; } } From 0d735c81b2add0da19f65600169f63e7f91e1597 Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 21:35:22 +0000 Subject: [PATCH 47/54] Added DESTROY state for deleting the call object --- include/aca_grpc.h | 2 +- src/comm/aca_grpc.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/aca_grpc.h b/include/aca_grpc.h index 6cb3bffd..039fd36a 100644 --- a/include/aca_grpc.h +++ b/include/aca_grpc.h @@ -58,7 +58,7 @@ class GoalStateProvisionerAsyncServer { AT the SENT state, a streaming call doesn't do anything; but a unary call deletes its own instance, since this call is already done. */ - enum CallStatus { INIT, SENT }; + enum CallStatus { INIT, SENT, DESTROY }; CallStatus status_; CallType type_; grpc::ServerContext ctx_; diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 06f87e4c..443e461d 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -219,7 +219,11 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: ACA_LOG_DEBUG("%s\n", "In SENT state, calling .Finish"); + streamingCall->status_ = AsyncGoalStateProvionerCallBase::CallStatus::DESTROY; streamingCall->stream_.Finish(Status::OK, baseCall); + break; + case AsyncGoalStateProvionerCallBase::CallStatus::DESTROY: + ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling .Finish"); ACA_LOG_DEBUG("%s\n", "In SENT state, calling gsOperationReply_.Clear()"); streamingCall->gsOperationReply_.Clear(); ACA_LOG_DEBUG("%s\n", "In SENT state, calling delete baseCall"); From 724e48a91335ee2e0a37e9149c15c7196dfc1f2d Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Tue, 16 Nov 2021 21:36:20 +0000 Subject: [PATCH 48/54] Added DESTROY state for deleting the call object --- src/comm/aca_grpc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 443e461d..23ccf747 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -224,9 +224,9 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( break; case AsyncGoalStateProvionerCallBase::CallStatus::DESTROY: ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling .Finish"); - ACA_LOG_DEBUG("%s\n", "In SENT state, calling gsOperationReply_.Clear()"); + ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling gsOperationReply_.Clear()"); streamingCall->gsOperationReply_.Clear(); - ACA_LOG_DEBUG("%s\n", "In SENT state, calling delete baseCall"); + ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling delete baseCall"); delete (PushGoalStatesStreamAsyncCall *)baseCall; break; default: From 49b5650feac7041c3c95af91ca78d211c47a1e8c Mon Sep 17 00:00:00 2001 From: Rio Zhu Date: Thu, 18 Nov 2021 17:42:07 +0000 Subject: [PATCH 49/54] Removed logs --- src/comm/aca_grpc.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 23ccf747..4c4c06cd 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -218,15 +218,11 @@ void GoalStateProvisionerAsyncServer::ProcessPushGoalStatesStreamAsyncCall( } break; case AsyncGoalStateProvionerCallBase::CallStatus::SENT: - ACA_LOG_DEBUG("%s\n", "In SENT state, calling .Finish"); streamingCall->status_ = AsyncGoalStateProvionerCallBase::CallStatus::DESTROY; streamingCall->stream_.Finish(Status::OK, baseCall); break; case AsyncGoalStateProvionerCallBase::CallStatus::DESTROY: - ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling .Finish"); - ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling gsOperationReply_.Clear()"); streamingCall->gsOperationReply_.Clear(); - ACA_LOG_DEBUG("%s\n", "In DESTROY state, calling delete baseCall"); delete (PushGoalStatesStreamAsyncCall *)baseCall; break; default: From a5c1da0033da60ae2e1bb79eabb01fa1ea358d10 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Fri, 10 Dec 2021 20:57:25 +0800 Subject: [PATCH 50/54] Update submodule Alcor to latest version (#273) --- alcor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alcor b/alcor index f3fd109c..97fc7b84 160000 --- a/alcor +++ b/alcor @@ -1 +1 @@ -Subproject commit f3fd109c65b6b80a960ef4aabb743f8a92788047 +Subproject commit 97fc7b8482320f121889dd4211f71b29a77d6275 From 74a78cf1bfe3cd1f26f4ecebde51de40e4b6cb06 Mon Sep 17 00:00:00 2001 From: lly00 Date: Sat, 11 Dec 2021 05:15:12 +0800 Subject: [PATCH 51/54] Add listeners for mulitcast and unicast consumers (#268) --- build/Dockerfile | 2 +- build/aca-machine-init.sh | 2 +- include/aca_comm_mgr.h | 4 + include/aca_message_pulsar_consumer.h | 51 ++++-- include/aca_message_pulsar_producer.h | 4 + src/CMakeLists.txt | 1 + src/aca_main.cpp | 14 +- src/comm/aca_comm_mgr.cpp | 32 ++++ src/comm/aca_message_pulsar_consumer.cpp | 164 ++++++++++------- src/comm/aca_message_pulsar_producer.cpp | 31 +++- test/CMakeLists.txt | 2 +- test/gtest/aca_test_arp.cpp | 123 ------------- test/gtest/aca_test_main.cpp | 36 +--- test/gtest/aca_test_mq.cpp | 222 +++++++++++++++++++++++ 14 files changed, 452 insertions(+), 236 deletions(-) create mode 100644 test/gtest/aca_test_mq.cpp diff --git a/build/Dockerfile b/build/Dockerfile index 68b102ea..8c1c7195 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -185,7 +185,7 @@ RUN echo "5--- installing openvswitch dependancies ---" && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ -ENV PULSAR_RELEASE_TAG='pulsar-2.6.1' +ENV PULSAR_RELEASE_TAG='pulsar-2.8.1' RUN echo "6--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 1a7162be..8ac558a5 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -199,7 +199,7 @@ echo "6--- installing openvswitch dependancies ---" && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ -PULSAR_RELEASE_TAG='pulsar-2.8.0' +PULSAR_RELEASE_TAG='pulsar-2.8.1' echo "7--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ diff --git a/include/aca_comm_mgr.h b/include/aca_comm_mgr.h index e658f303..05734ee5 100644 --- a/include/aca_comm_mgr.h +++ b/include/aca_comm_mgr.h @@ -28,6 +28,9 @@ class Aca_Comm_Manager { int deserialize(const unsigned char *mq_buffer, size_t buffer_length, alcor::schema::GoalState &parsed_struct); + int deserialize(const unsigned char *mq_buffer, size_t buffer_length, + alcor::schema::GoalStateV2 &parsed_struct); + int update_goal_state(alcor::schema::GoalState &goal_state_message, alcor::schema::GoalStateOperationReply &gsOperationReply); @@ -47,6 +50,7 @@ class Aca_Comm_Manager { void print_goal_state(alcor::schema::GoalState parsed_struct); void print_goal_state(alcor::schema::GoalStateV2 parsed_struct); + }; } // namespace aca_comm_manager #endif diff --git a/include/aca_message_pulsar_consumer.h b/include/aca_message_pulsar_consumer.h index 5732379d..4572c454 100644 --- a/include/aca_message_pulsar_consumer.h +++ b/include/aca_message_pulsar_consumer.h @@ -20,6 +20,8 @@ #include "pulsar/ConsumerConfiguration.h" #include "pulsar/Message.h" #include "pulsar/Result.h" +#include "pulsar/ConsumerType.h" +#include "pulsar/KeySharedPolicy.h" using namespace pulsar; @@ -29,35 +31,58 @@ namespace aca_message_pulsar { class ACA_Message_Pulsar_Consumer { private: - string brokers_list; //IP addresses of pulsar brokers, format: pulsar:://:, example: pulsar://10.213.43.188:9092 + string brokers_list; // IP addresses of pulsar brokers, format: pulsar:://:, example: pulsar://10.213.43.188:9092 - string subscription_name; //Subscription name of the pulsar consumer + string multicast_subscription_name; // Subscription name of the multicast pulsar consumer + string unicast_subscription_name; // Subscription name of the unicast pulsar consumer - string topic_name; //A string representation of the topic to be consumed, for example: /hostid/00000000-0000-0000-0000-000000000000/netwconf/ + string multicast_topic_name; //A string representation of the topic to be consumed, for example: /hostid/00000000-0000-0000-0000-000000000000/netwconf/ + string unicast_topic_name; - ConsumerConfiguration consumer_config; //Configuration of the pulsar consumer + ConsumerConfiguration multicast_consumer_config; //Configuration of the mulitcast pulsar consumer + ConsumerConfiguration unicast_consumer_config; //Configuration of the unicast pulsar consumer - Client *ptr_client; //A pointer to the pulsar client + Client *ptr_multicast_client; //A pointer to the multicast pulsar client + Client *ptr_unicast_client; //A pointer to the unicast pulsar client + + Consumer multicast_consumer; + Consumer unicast_consumer; + + private: + void setMulticastSubscriptionName(string subscription_name); + + void setUnicastSubscriptionName(string subscription_name); + + void setBrokers(string brokers); + + void setMulticastTopicName(string topic); + + void setUnicastTopicName(string topic); + + public: - ACA_Message_Pulsar_Consumer(string brokers, string subscription_name); + ACA_Message_Pulsar_Consumer(string topic, string brokers, string subscription_name); ~ACA_Message_Pulsar_Consumer(); string getBrokers() const; - string getLastTopicName() const; + string getMulticastTopicName() const; - string getSubscriptionName() const; + string getUnicastTopicName() const; - void setSubscriptionName(string subscription_name); + string getMulticastSubscriptionName() const; - bool consumeDispatched(string topic); + string getUnicastSubscriptionName() const; - private: - void setBrokers(string brokers); + bool multicastConsumerDispatched(); + + bool unicastConsumerDispatched(int stickyHash); + + //static void listener(Consumer consumer, const Message& message); - void setLastTopicName(string topic); + }; } // namespace aca_message_pulsar diff --git a/include/aca_message_pulsar_producer.h b/include/aca_message_pulsar_producer.h index 0990b620..269ad7e4 100644 --- a/include/aca_message_pulsar_producer.h +++ b/include/aca_message_pulsar_producer.h @@ -50,8 +50,12 @@ class ACA_Message_Pulsar_Producer { bool publish(string message); + bool publish(string message, string key); + + private: void setBrokers(string brokers); + }; } // aca_message_pulsar diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3accc472..5a0f4992 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,6 +103,7 @@ target_link_libraries(AlcorControlAgent grpc) target_link_libraries(AlcorControlAgent ${PROTOBUF_LIBRARY}) target_link_libraries(AlcorControlAgent ${_GRPC_GRPCPP_UNSECURE}) + add_dependencies(AlcorControlAgentLib proto grpc) add_subdirectory(proto3) add_subdirectory(grpc) \ No newline at end of file diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 30e338ac..8e4b52fe 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -42,7 +42,7 @@ using std::string; // Defines #define ACALOGNAME "AlcorControlAgent" static char EMPTY_STRING[] = ""; -static char BROKER_LIST[] = "pulsar://localhost:6502"; +static char BROKER_LIST[] = "pulsar://localhost:6650"; static char PULSAR_TOPIC[] = "Host-ts-1"; static char PULSAR_SUBSCRIPTION_NAME[] = "Test-Subscription"; static char GRPC_SERVER_PORT[] = "50001"; @@ -59,6 +59,7 @@ GoalStateProvisionerClientImpl *g_grpc_client = NULL; string g_broker_list = EMPTY_STRING; string g_pulsar_topic = EMPTY_STRING; string g_pulsar_subsription_name = EMPTY_STRING; +string g_pulsar_hashed_key = "0"; string g_grpc_server_port = EMPTY_STRING; string g_ofctl_command = EMPTY_STRING; string g_ofctl_target = EMPTY_STRING; @@ -183,7 +184,7 @@ int main(int argc, char *argv[]) signal(SIGINT, aca_signal_handler); signal(SIGTERM, aca_signal_handler); - while ((option = getopt(argc, argv, "a:p:b:h:g:s:c:t:o:md")) != -1) { + while ((option = getopt(argc, argv, "a:p:b:h:g:k:s:c:t:o:md")) != -1) { switch (option) { case 'a': g_ncm_address = optarg; @@ -200,6 +201,9 @@ int main(int argc, char *argv[]) case 'g': g_pulsar_subsription_name = optarg; break; + case 'k': + g_pulsar_hashed_key = optarg; + break; case 's': g_grpc_server_port = optarg; break; @@ -226,6 +230,7 @@ int main(int argc, char *argv[]) "\t\t[-b pulsar broker list]\n" "\t\t[-h pulsar host topic to listen]\n" "\t\t[-g pulsar subscription name]\n" + "\t\t[-k pulsar hashed key]\n" "\t\t[-s gRPC server port\n" "\t\t[-c ofctl command]\n" "\t\t[-m enable demo mode]\n" @@ -287,8 +292,9 @@ int main(int argc, char *argv[]) //// monitor br-tun for arp request message //ACA_OVS_Control::get_instance().monitor("br-tun", "resume"); - ACA_Message_Pulsar_Consumer network_config_consumer(g_broker_list, g_pulsar_subsription_name); - rc = network_config_consumer.consumeDispatched(g_pulsar_topic); + ACA_Message_Pulsar_Consumer network_config_consumer(g_pulsar_topic, g_broker_list, g_pulsar_subsription_name); + //network_config_consumer.multicastConsumerDispatched(); + network_config_consumer.unicastConsumerDispatched(atoi(g_pulsar_hashed_key.c_str())); pause(); aca_cleanup(); diff --git a/src/comm/aca_comm_mgr.cpp b/src/comm/aca_comm_mgr.cpp index 8c36fabf..7e2f1953 100644 --- a/src/comm/aca_comm_mgr.cpp +++ b/src/comm/aca_comm_mgr.cpp @@ -38,6 +38,38 @@ Aca_Comm_Manager &Aca_Comm_Manager::get_instance() return instance; } +int Aca_Comm_Manager::deserialize(const unsigned char *mq_buffer, + size_t buffer_length, GoalStateV2 &parsed_struct) +{ + int rc; + + if (mq_buffer == NULL) { + rc = -EINVAL; + ACA_LOG_ERROR("Empty mq_buffer data rc: %d\n", rc); + return rc; + } + + if (parsed_struct.IsInitialized() == false) { + rc = -EINVAL; + ACA_LOG_ERROR("Uninitialized parsed_struct rc: %d\n", rc); + return rc; + } + + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + if (parsed_struct.ParseFromArray(mq_buffer, buffer_length)) { + ACA_LOG_INFO("%s", "Successfully converted message to protobuf struct\n"); + + return EXIT_SUCCESS; + } else { + rc = -EXIT_FAILURE; + ACA_LOG_ERROR("Failed to convert message to protobuf struct rc: %d\n", rc); + return rc; + } +} + int Aca_Comm_Manager::deserialize(const unsigned char *mq_buffer, size_t buffer_length, GoalState &parsed_struct) { diff --git a/src/comm/aca_message_pulsar_consumer.cpp b/src/comm/aca_message_pulsar_consumer.cpp index ee7723df..5bbc9125 100644 --- a/src/comm/aca_message_pulsar_consumer.cpp +++ b/src/comm/aca_message_pulsar_consumer.cpp @@ -24,25 +24,66 @@ using pulsar::ConsumerConfiguration; using pulsar::Consumer; using pulsar::Message; using pulsar::Result; +using pulsar::KeySharedPolicy; +using pulsar::StickyRange; namespace aca_message_pulsar { -ACA_Message_Pulsar_Consumer::ACA_Message_Pulsar_Consumer(string brokers, string subscription_name) + +void listener(Consumer consumer, const Message& message){ + alcor::schema::GoalStateV2 deserialized_GoalState; + alcor::schema::GoalStateOperationReply gsOperationalReply; + int rc; + Result result; + + ACA_LOG_DEBUG("\n<=====incoming message: %s\n", + message.getDataAsString().c_str()); + + rc = Aca_Comm_Manager::get_instance().deserialize( + (unsigned char *)message.getData(), message.getLength(), deserialized_GoalState); + if (rc == EXIT_SUCCESS) { + rc = Aca_Comm_Manager::get_instance().update_goal_state( + deserialized_GoalState, gsOperationalReply); + + + if (rc != EXIT_SUCCESS) { + ACA_LOG_ERROR("Failed to update host with latest goal state, rc=%d.\n", rc); + } else { + ACA_LOG_INFO("Successfully updated host with latest goal state %d.\n", rc); + } + + } else { + ACA_LOG_ERROR("Deserialization failed with error code %d.\n", rc); + } + + // Now acknowledge message + consumer.acknowledge(message.getMessageId()); +} + +ACA_Message_Pulsar_Consumer::ACA_Message_Pulsar_Consumer(string topic, string brokers, string subscription_name) { + setUnicastTopicName(topic); + setMulticastTopicName(topic); setBrokers(brokers); - setSubscriptionName(subscription_name); + setUnicastSubscriptionName(subscription_name); + setMulticastSubscriptionName(subscription_name); ACA_LOG_DEBUG("Broker list: %s\n", this->brokers_list.c_str()); - ACA_LOG_DEBUG("Consumer subscription name: %s\n", this->subscription_name.c_str()); - - // Create the client - this->ptr_client= new Client(brokers); + ACA_LOG_DEBUG("Unicast consumer topic name: %s\n", this->unicast_topic_name.c_str()); + ACA_LOG_DEBUG("Unicast consumer subscription name: %s\n", this->unicast_subscription_name.c_str()); + ACA_LOG_DEBUG("Multicast consumer topic name: %s\n", this->multicast_topic_name.c_str()); + ACA_LOG_DEBUG("Multicast consumer subscription name: %s\n", this->multicast_subscription_name.c_str()); + + // Create the clients + //this->ptr_multicast_client= new Client(brokers); + this->ptr_unicast_client = new Client(brokers); } ACA_Message_Pulsar_Consumer::~ACA_Message_Pulsar_Consumer() { - delete this->ptr_client; + delete this->ptr_multicast_client; + delete this->ptr_unicast_client; } string ACA_Message_Pulsar_Consumer::getBrokers() const @@ -50,91 +91,86 @@ string ACA_Message_Pulsar_Consumer::getBrokers() const return this->brokers_list; } -string ACA_Message_Pulsar_Consumer::getLastTopicName() const +string ACA_Message_Pulsar_Consumer::getMulticastTopicName() const { - return this->topic_name; + return this->multicast_topic_name; } -string ACA_Message_Pulsar_Consumer::getSubscriptionName() const +string ACA_Message_Pulsar_Consumer::getMulticastSubscriptionName() const { - return this->subscription_name; + return this->multicast_subscription_name; } -void ACA_Message_Pulsar_Consumer::setSubscriptionName(string subscription_name) +string ACA_Message_Pulsar_Consumer::getUnicastTopicName() const { - this->subscription_name = subscription_name; + return this->unicast_topic_name; } -bool ACA_Message_Pulsar_Consumer::consumeDispatched(string topic) +string ACA_Message_Pulsar_Consumer::getUnicastSubscriptionName() const { - alcor::schema::GoalState deserialized_GoalState; - alcor::schema::GoalStateOperationReply gsOperationalReply; - int rc; - int overall_rc = EXIT_SUCCESS; + return this->unicast_subscription_name; +} + + +bool ACA_Message_Pulsar_Consumer::unicastConsumerDispatched(int stickyHash){ Result result; - Message message; Consumer consumer; - result = this->ptr_client->subscribe(topic,this->subscription_name,this->consumer_config,consumer); + KeySharedPolicy keySharedPolicy; + keySharedPolicy.setKeySharedMode(STICKY); + // Set sticky ranges with specified hash value + + StickyRange stickyRange = std::make_pair(stickyHash,stickyHash); + keySharedPolicy.setStickyRanges({stickyRange}); + + //Use key shared mode + this->unicast_consumer_config.setConsumerType(ConsumerKeyShared).setKeySharedPolicy(keySharedPolicy).setMessageListener(listener); + result = this->ptr_unicast_client->subscribe(this->unicast_topic_name,this->unicast_subscription_name,this->unicast_consumer_config,this->unicast_consumer); if (result != Result::ResultOk){ - ACA_LOG_ERROR("Failed to subscribe topic: %s\n", topic.c_str()); + ACA_LOG_ERROR("Failed to subscribe unicast topic: %s\n", this->unicast_topic_name.c_str()); return EXIT_FAILURE; } - ACA_LOG_DEBUG("Consumer consuming messages from topic: %s\n", topic.c_str()); - - //Receive message - while(true){ - result = consumer.receive(message); + return EXIT_SUCCESS; +} - if (result != Result::ResultOk) { - ACA_LOG_ERROR("Failed to receive message from topic: %s\n",topic.c_str()); - return EXIT_FAILURE; - } +bool ACA_Message_Pulsar_Consumer::multicastConsumerDispatched(){ + Result result; - else{ - // Print the ordering key (if any) - if (message.hasOrderingKey()) { - ACA_LOG_DEBUG("%s -> ", message.getOrderingKey().c_str()); - } - // Print the payload - ACA_LOG_DEBUG("\n<=====incoming message: %s\n", - message.getDataAsString().c_str()); - - rc = Aca_Comm_Manager::get_instance().deserialize( - (unsigned char *)message.getData(), message.getLength(), deserialized_GoalState); - if (rc == EXIT_SUCCESS) { - rc = Aca_Comm_Manager::get_instance().update_goal_state( - deserialized_GoalState, gsOperationalReply); - - // TODO: send gsOperationalReply back to controller - - if (rc != EXIT_SUCCESS) { - ACA_LOG_ERROR("Failed to update host with latest goal state, rc=%d.\n", rc); - overall_rc = rc; - } else { - ACA_LOG_INFO("Successfully updated host with latest goal state %d.\n", rc); - } - } else { - ACA_LOG_ERROR("Deserialization failed with error code %d.\n", rc); - overall_rc = rc; - } - - // Now acknowledge message - consumer.acknowledge(message); - } + // Use the default exclusive mode + this->multicast_consumer_config.setMessageListener(listener); + result = this->ptr_multicast_client->subscribe(this->multicast_topic_name,this->multicast_subscription_name,this->multicast_consumer_config,this->multicast_consumer); + if (result != Result::ResultOk){ + ACA_LOG_ERROR("Failed to subscribe multicast topic: %s\n", this->multicast_topic_name.c_str()); + return EXIT_FAILURE; } - return overall_rc; + return EXIT_SUCCESS; } + void ACA_Message_Pulsar_Consumer::setBrokers(string brokers) { this->brokers_list = brokers; } -void ACA_Message_Pulsar_Consumer::setLastTopicName(string topic) +void ACA_Message_Pulsar_Consumer::setMulticastTopicName(string topic) +{ + this->multicast_topic_name = topic; +} + +void ACA_Message_Pulsar_Consumer::setMulticastSubscriptionName(string subscription_name) +{ + this->multicast_subscription_name = subscription_name; +} + +void ACA_Message_Pulsar_Consumer::setUnicastTopicName(string topic) +{ + this->unicast_topic_name = topic; +} + +void ACA_Message_Pulsar_Consumer::setUnicastSubscriptionName(string subscription_name) { - this->topic_name = topic; + this->unicast_subscription_name = subscription_name; } } // namespace aca_message_pulsar diff --git a/src/comm/aca_message_pulsar_producer.cpp b/src/comm/aca_message_pulsar_producer.cpp index 553242fa..115e50d0 100644 --- a/src/comm/aca_message_pulsar_producer.cpp +++ b/src/comm/aca_message_pulsar_producer.cpp @@ -77,14 +77,43 @@ bool ACA_Message_Pulsar_Producer::publish(string message) // Flush all produced messages producer.flush(); + producer.close(); return EXIT_SUCCESS; } +bool ACA_Message_Pulsar_Producer::publish(string message, string orderingKey) +{ + Result result; + + // Create a producer + Producer producer; + result = this->ptr_client->createProducer(this->topic_name,producer); + if(result != ResultOk){ + ACA_LOG_ERROR("Failed to create producer, result=%d.\n", result); + return EXIT_FAILURE; + } + + // Create a message + Message msg = MessageBuilder().setContent(message).setOrderingKey(orderingKey).build(); + result = producer.send(msg); + if(result != ResultOk){ + ACA_LOG_ERROR("Failed to send message %s.\n", message.c_str()); + return EXIT_FAILURE; + } + + ACA_LOG_INFO("Successfully send message %s\n", message.c_str()); + + // Flush all produced messages + producer.flush(); + producer.close(); + return EXIT_SUCCESS; + +} void ACA_Message_Pulsar_Producer::setBrokers(string brokers) { //TODO: validate string as IP address this->brokers_list = brokers; } -} // namespace aca_message_pulsar \ No newline at end of file +} // namespace aca_message_pulsar diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index abfa55e9..5e9c4e4b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,7 +49,7 @@ add_executable( gtest/aca_test_zeta_programming.cpp gtest/aca_test_arp.cpp gtest/aca_test_on_demand.cpp -) + gtest/aca_test_mq.cpp) # Link test executable against gtest & gtest_main target_link_libraries(aca_tests gtest gtest_main) diff --git a/test/gtest/aca_test_arp.cpp b/test/gtest/aca_test_arp.cpp index 13e99421..4c1ded4f 100644 --- a/test/gtest/aca_test_arp.cpp +++ b/test/gtest/aca_test_arp.cpp @@ -198,129 +198,6 @@ TEST(arp_request_test_cases, arps_recv_valid) // ./build/tests/aca_tests --gtest_also_run_disabled_tests --gtest_filter=arp_request_test_cases.DISABLED_l2_arp_test_PARENT -c 10.213.43.188 // -TEST(arp_request_test_cases, DISABLED_l2_arp_test_one_machine) -{ - string cmd_string; - arp_config stArpCfgIn; - int overall_rc; - - aca_test_reset_environment(); - - // monitor br-tun for arp request message - ovs_monitor_thread = - new thread(bind(&ACA_OVS_Control::monitor, &ACA_OVS_Control::get_instance(), "br-tun", "resume")); - ovs_monitor_thread->detach(); - - GoalState GoalState_builder; - - SubnetState *new_subnet_states = GoalState_builder.add_subnet_states(); - new_subnet_states->set_operation_type(OperationType::INFO); - SubnetConfiguration *SubnetConiguration_builder = - new_subnet_states->mutable_configuration(); - SubnetConiguration_builder->set_revision_number(1); - SubnetConiguration_builder->set_vpc_id(vpc_id_1); - SubnetConiguration_builder->set_id(subnet_id_1); - SubnetConiguration_builder->set_cidr(subnet1_cidr); - SubnetConiguration_builder->set_tunnel_id(123); - - auto *subnetConfig_GatewayBuilder(new SubnetConfiguration_Gateway); - subnetConfig_GatewayBuilder->set_ip_address(subnet1_gw_ip); - subnetConfig_GatewayBuilder->set_mac_address(subnet1_gw_mac); - SubnetConiguration_builder->set_allocated_gateway(subnetConfig_GatewayBuilder); - - NeighborState *new_neighbor_states = GoalState_builder.add_neighbor_states(); - - new_neighbor_states->set_operation_type(OperationType::CREATE); - - // fill in neighbor state structs - NeighborConfiguration *NeighborConfiguration_builder = - new_neighbor_states->mutable_configuration(); - NeighborConfiguration_builder->set_revision_number(1); - - NeighborConfiguration_builder->set_vpc_id(vpc_id_1); - NeighborConfiguration_builder->set_id(port_id_3); - NeighborConfiguration_builder->set_mac_address(vmac_address_3); - NeighborConfiguration_builder->set_host_ip_address("172.16.62.158"); - - NeighborConfiguration_FixedIp *FixedIp_builder = - NeighborConfiguration_builder->add_fixed_ips(); - FixedIp_builder->set_neighbor_type(NeighborType::L2); - FixedIp_builder->set_subnet_id(subnet_id_1); - FixedIp_builder->set_ip_address(vip_address_3); - - GoalStateOperationReply gsOperationalReply; - - overall_rc = Aca_Comm_Manager::get_instance().update_goal_state( - GoalState_builder, gsOperationalReply); - ASSERT_EQ(overall_rc, EXIT_SUCCESS); - - NeighborConfiguration_builder->set_mac_address(vmac_address_1); - FixedIp_builder->set_ip_address(vip_address_1); - - overall_rc = Aca_Comm_Manager::get_instance().update_goal_state( - GoalState_builder, gsOperationalReply); - ASSERT_EQ(overall_rc, EXIT_SUCCESS); - - - // create docker instances for test - // con1 - overall_rc = Aca_Net_Config::get_instance().execute_system_command( - "docker run -itd --cap-add=NET_ADMIN --name con1 --net=none alpine sh"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - cmd_string = "ovs-docker add-port br-int eth1 con1 --macaddress=" + vmac_address_1 + " --ipaddress="+vip_address_1 + "/24"; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - overall_rc = EXIT_SUCCESS; - - cmd_string = "ovs-docker set-vlan br-int eth1 con1 1"; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - overall_rc = EXIT_SUCCESS; - - - // con2 - overall_rc = Aca_Net_Config::get_instance().execute_system_command( - "docker run -itd --cap-add=NET_ADMIN --name con2 --net=none alpine sh"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - cmd_string = "ovs-docker add-port br-int eth1 con2 --macaddress=" + vmac_address_3 + " --ipaddress="+vip_address_3 + "/24"; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - cmd_string = "ovs-docker set-vlan br-int eth1 con2 1"; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - // test ping - cmd_string = "docker exec con1 ping -c1 " + vip_address_3; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - overall_rc = EXIT_SUCCESS; - - cmd_string = "docker exec con2 ping -c1 " + vip_address_1; - overall_rc = Aca_Net_Config::get_instance().execute_system_command(cmd_string); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - overall_rc = EXIT_SUCCESS; - - - //clean up - overall_rc = Aca_Net_Config::get_instance().execute_system_command( - "ovs-docker del-ports br-int con1"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - overall_rc = Aca_Net_Config::get_instance().execute_system_command( - "ovs-docker del-ports br-int con2"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - overall_rc = Aca_Net_Config::get_instance().execute_system_command("docker rm con1 -f"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); - - overall_rc = Aca_Net_Config::get_instance().execute_system_command("docker rm con2 -f"); - EXPECT_EQ(overall_rc, EXIT_SUCCESS); -} - - TEST(arp_request_test_cases, DISABLED_l2_arp_test_PARENT) { diff --git a/test/gtest/aca_test_main.cpp b/test/gtest/aca_test_main.cpp index 26354cc5..0ee784b8 100644 --- a/test/gtest/aca_test_main.cpp +++ b/test/gtest/aca_test_main.cpp @@ -19,6 +19,10 @@ #include "aca_grpc.h" #include "aca_grpc_client.h" #include "aca_message_pulsar_producer.h" +#include "aca_message_pulsar_consumer.h" +#include "aca_ovs_control.h" +#include "aca_net_config.h" +#include "aca_comm_mgr.h" #include /* for getopt */ #include #include @@ -26,7 +30,8 @@ using namespace std; using namespace aca_message_pulsar; - +using aca_net_config::Aca_Net_Config; +using aca_comm_manager::Aca_Comm_Manager; #define ACALOGNAME "AlcorControlAgentTest" // Global variables @@ -62,12 +67,10 @@ std::atomic_ulong g_total_update_GS_time(0); bool g_debug_mode = true; bool g_demo_mode = false; -string remote_ip_1 = "172.17.0.2"; // for docker network -string remote_ip_2 = "172.17.0.3"; // for docker network +string remote_ip_1="172.17.0.2"; // for docker network +string remote_ip_2= "172.17.0.3"; // for docker network uint neighbors_to_create = 10; -static string mq_broker_ip = "pulsar://localhost:6650"; //for the broker running in localhost -static string mq_test_topic = "my-topic"; int processor_count = std::thread::hardware_concurrency(); /* From previous tests, we found that, for x number of cores, @@ -78,29 +81,6 @@ int processor_count = std::thread::hardware_concurrency(); */ int thread_pools_size = (processor_count == 0) ? 1 : ((ceil(1.3 * processor_count)) / 2); -// -// Test suite: pulsar_test_cases -// -// Testing the pulsar implementation where AlcorControlAgent is the consumer -// and aca_test is acting as producer -// Note: it will require a pulsar setup on localhost therefore this test is DISABLED by default -// it can be executed by: -// -// aca_tests --gtest_also_run_disabled_tests --gtest_filter=*DISABLED_pulsar_consumer_test -// -TEST(pulsar_test_cases, DISABLED_pulsar_consumer_test) -{ - int retcode = 0; - const int MESSAGES_TO_SEND = 10; - string message = "Test Message"; - - ACA_Message_Pulsar_Producer producer(mq_broker_ip, mq_test_topic); - - for (int i = 0; i < MESSAGES_TO_SEND; i++) { - retcode = producer.publish(message); - EXPECT_EQ(retcode, EXIT_SUCCESS); - } -} static void aca_cleanup() { diff --git a/test/gtest/aca_test_mq.cpp b/test/gtest/aca_test_mq.cpp new file mode 100644 index 00000000..f5946d94 --- /dev/null +++ b/test/gtest/aca_test_mq.cpp @@ -0,0 +1,222 @@ +// +// Created by FangJ on 2021/11/29. +// +// MIT License +// Copyright(c) 2020 Futurewei Cloud +// +// Permission is hereby granted, +// free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software 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. + +#include "aca_log.h" +#include "gtest/gtest.h" +#include "goalstate.pb.h" +#include "aca_grpc.h" +#include "aca_grpc_client.h" +#include "aca_message_pulsar_producer.h" +#include "aca_message_pulsar_consumer.h" +#include "aca_ovs_l2_programmer.h" +#include "aca_ovs_control.h" +#define ACALOGNAME "AlcorControlAgentTest" + +using namespace std; +using namespace aca_message_pulsar; +using namespace aca_ovs_l2_programmer; +using aca_ovs_control::ACA_OVS_Control; + + +extern string project_id; +extern string vpc_id_1; +extern string vpc_id_2; +extern string subnet_id_1; +extern string subnet_id_2; +extern string port_id_1; +extern string port_id_2; +extern string port_id_3; +extern string port_id_4; +extern string port_name_1; +extern string port_name_2; +extern string port_name_3; +extern string port_name_4; +extern string vmac_address_1; +extern string vmac_address_2; +extern string vmac_address_3; +extern string vmac_address_4; +extern string vip_address_1; +extern string vip_address_2; +extern string vip_address_3; +extern string vip_address_4; +extern string remote_ip_1; // for docker network +extern string remote_ip_2; // for docker network +extern bool g_demo_mode; + +extern void aca_test_reset_environment(); +extern void aca_test_create_default_port_state(PortState *new_port_states); +extern void aca_test_create_default_subnet_state(SubnetState *new_subnet_states); +extern void aca_test_1_neighbor_CREATE_DELETE(NeighborType input_neighbor_type); +extern void aca_test_1_neighbor_CREATE_DELETE_V2(NeighborType input_neighbor_type); +extern void aca_test_1_port_CREATE_plus_neighbor_CREATE(NeighborType input_neighbor_type); +extern void aca_test_1_port_CREATE_plus_neighbor_CREATE_V2(NeighborType input_neighbor_type); +extern void aca_test_10_neighbor_CREATE(NeighborType input_neighbor_type); +extern void aca_test_10_neighbor_CREATE_V2(NeighborType input_neighbor_type); +extern void aca_test_1_port_CREATE_plus_N_neighbors_CREATE(NeighborType input_neighbor_type, + uint neighbors_to_create); +extern void +aca_test_1_port_CREATE_plus_N_neighbors_CREATE_V2(NeighborType input_neighbor_type, + uint neighbors_to_create); + +static string mq_broker_ip = "pulsar://localhost:6650"; //for the broker running in localhost +static string mq_test_topic = "Host-ts-1"; +static string mq_subscription = "test_subscription"; +static string mq_key="9192a4d4-ffff-4ece-b3f0-8d36e3d88001"; // 3dda2801-d675-4688-a63f-dcda8d327f50 9192a4d4-ffff-4ece-b3f0-8d36e3d88001 +static int mq_hash=49775; // 21485 49775 + +// +// Test suite: pulsar_test_cases +// +// Note: it requires a pulsar setup on localhost therefore this test is DISABLED by default. +// You will need three terminals: +// Terminal(1): run pulsar standalone. +// Terminal(2): run pulsar consumer test case. +// Terminal(3): run pulsar producer test cases. + + +// This case tests the pulsar consumer implementation. +// First run this case by executing: +// ./aca_tests --gtest_also_run_disabled_tests --gtest_filter=*DISABLED_pulsar_consumer_test +// Then run the following producer test cases. + +TEST(pulsar_test_cases, DISABLED_pulsar_consumer_test) +{ + bool previous_demo_mode = g_demo_mode; + g_demo_mode = true; + + aca_test_reset_environment(); + + ACA_Message_Pulsar_Consumer consumer(mq_test_topic, mq_broker_ip, mq_subscription); + consumer.multicastConsumerDispatched(); + pause(); + + g_demo_mode = previous_demo_mode; +} + +// sudo ./aca_tests --gtest_also_run_disabled_tests --gtest_filter=*DISABLED_pulsar_unicast_consumer_test +TEST(pulsar_test_cases, DISABLED_pulsar_unicast_consumer_test) +{ + string cmd_string; + + + bool previous_demo_mode = g_demo_mode; + g_demo_mode = true; + + aca_test_reset_environment(); + + ACA_Message_Pulsar_Consumer consumer(mq_test_topic, mq_broker_ip, mq_subscription); + consumer.unicastConsumerDispatched(mq_hash); + pause(); + + g_demo_mode = previous_demo_mode; +} + + +// This case tests the pulsar producer implementation and publishes a GoalState to the subscribed topic. +// First run pulsar_consumer_test then execute +// sudo ./aca_tests --gtest_also_run_disabled_tests --gtest_filter=*DISABLED_pulsar_hash_producer_test +TEST(pulsar_test_cases, DISABLED_pulsar_hash_producer_test) +{ + int retcode = 0; + int overall_rc=0; + int length=1000; + ulong not_care_culminative_time; + string cmd_string; + string GoalStateString; + unsigned char serializedGoalState[length]; + + GoalState GoalState_builder; + PortState *new_port_states = GoalState_builder.add_port_states(); + SubnetState *new_subnet_states = GoalState_builder.add_subnet_states(); + + ACA_OVS_L2_Programmer::get_instance().execute_ovsdb_command( + "del-br br-int", not_care_culminative_time, overall_rc); + + ACA_OVS_L2_Programmer::get_instance().execute_ovsdb_command( + "del-br br-tun", not_care_culminative_time, overall_rc); + + overall_rc = ACA_OVS_L2_Programmer::get_instance().setup_ovs_bridges_if_need(); + ASSERT_EQ(overall_rc, EXIT_SUCCESS); + overall_rc = EXIT_SUCCESS; + + // fill in port state structs + aca_test_create_default_port_state(new_port_states); + + // fill in subnet state structs + aca_test_create_default_subnet_state(new_subnet_states); + + if(GoalState_builder.SerializeToString(&GoalStateString)){ + ACA_LOG_INFO("%s","Successfully covert GoalState to message\n"); + } + + ACA_Message_Pulsar_Producer producer(mq_broker_ip, mq_test_topic); + retcode = producer.publish(GoalStateString,mq_key); + EXPECT_EQ(retcode, EXIT_SUCCESS); + + ACA_LOG_INFO("%s","Waiting for GoalState update.\n"); + sleep(1); + + ACA_OVS_L2_Programmer::get_instance().execute_ovsdb_command( + "get Interface " + port_name_1 + " ofport", not_care_culminative_time, overall_rc); + EXPECT_EQ(overall_rc, EXIT_SUCCESS); + overall_rc = EXIT_SUCCESS; + +} + +// This case tests the pulsar producer implementation and publishes a GoalStateV2 to the subscribed topic. +// First run pulsar_consumer_test then execute +// sudo ./aca_tests --gtest_also_run_disabled_tests --gtest_filter=*DISABLED_pulsar_producer_testv2 + +TEST(pulsar_test_cases, DISABLED_pulsar_producer_testv2) +{ + int retcode=0; + int overall_rc=0; + ulong not_care_culminative_time; + string cmd_string; + string GoalStateString; + + aca_test_reset_environment(); + + GoalStateV2 GoalState_builder; + PortState new_port_states; + SubnetState new_subnet_states; + + aca_test_create_default_port_state(&new_port_states); + auto &port_states_map = *GoalState_builder.mutable_port_states(); + port_states_map[port_id_1] = new_port_states; + + aca_test_create_default_subnet_state(&new_subnet_states); + auto &subnet_states_map = *GoalState_builder.mutable_subnet_states(); + subnet_states_map[subnet_id_1] = new_subnet_states; + + if(GoalState_builder.SerializeToString(&GoalStateString)){ + ACA_LOG_INFO("%s","Successfully covert GoalStateV2 to message\n"); + } + + ACA_Message_Pulsar_Producer producer(mq_broker_ip, mq_test_topic); + retcode = producer.publish(GoalStateString); + EXPECT_EQ(retcode, EXIT_SUCCESS); + + ACA_LOG_INFO("%s","Waiting for GoalStateV2 update.\n"); + sleep(2); + + ACA_OVS_L2_Programmer::get_instance().execute_ovsdb_command( + "get Interface " + port_name_1 + " ofport", not_care_culminative_time, overall_rc); + EXPECT_EQ(overall_rc, EXIT_SUCCESS); + overall_rc = EXIT_SUCCESS; + +} \ No newline at end of file From 3bb4ee3017d4f2b6197d2c21cc96625e54eac1be Mon Sep 17 00:00:00 2001 From: Rio Zhu <32083634+zzxgzgz@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:26:36 -0800 Subject: [PATCH 52/54] ACA task framework refactoring (#275) * Changed ACA's openflow version from 1.3 to 1.0 * Added tunnel_id printout, and commented out some unused code * Try to make packet out to the bridge based on the of_connection_id * Changed more code to let packet out based on of_connection_i * Changed implementation for adding/removing switches in of_controller, in order to prevent deadlock * Try to make on-demand packet_out based on the connection_id, rather than bridge name * Added logs, in order to investigate why ofconnection dropped * Suspect removing switches with empty name causes the problem * Modifed arp_responder to avoid calling NCM * Added local map lookup * Initiate marl integration for packet-in stress testing * Move libfluid packet-in parsing also to async scheduler, to release message_callback full capacity of receiving packets * Break parse ARP job * Test setting specific worker thread number * Do not break parse job but set specific worker size This reverts commit 42716a10cb93873df68b4270b51713b50b2ba1fb. * Try to make atomic counter for packet_in * Try to make atomic counter for packet_in * Try to make atomic counter for packet_in * Try to make atomic counter for packet_in * Try to make atomic counter for packet_in * Try to make atomic counter for packet_in * Added sleep 100 us in marl code when packet in * Added packet_out_counter, also made the counters global * Added packet_out_counter, also made the counters global * Print out both counters every 1 second * Commented out arp_recv and see if the bottleneck is in the on-demand engine * Changed packet_out_counter++ to the start of parse_packet, then return immediately * Changed packet_out_counter++ to the start of parse_packet, then return immediately * Change it to right inside the arp ether type * Change it to before arp ether type * Change it to before vlan ether type * Change it to before * Commented out ACA_LOG_INFOs on the packet_in to packet_out path * Confirm on_demand_engine is already fast * Put the count into the arp_recv * Put the count into the arp_recv * Added fmt library and sample fmt code * Set counter before sprintf to get a baseline for comparison * Set counter before sprintf to get a baseline for comparison * Set counter before sprintf to get a baseline for comparison * Set counter after 5 sprintf and string.append * Set counter after 5 sprintf and string.append * set counter after for loops * set counter after if statement * set counter before return * _serialize_arp_message isn't a bottleneck? * have to do it again with 4 switches in cbench * after first five sprintf and string.append * after for loops * before return * Try to rewrite _serialize_arp_message with fmt code * try to call condense format_to to fewer ones * comment out append to see if it takes a lot of time * Try to use FMT_COMPILE when calling format_to * do test with fmt * Check qps before packet out * let packet out go and test again * Comment out time recording and test again * put counter before is_found * put counter at the beginning of packet_out * add packet out counter to packet out * place counter in ofcontroller::packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * place counter in create_packet_out * testing without std::move * testing without std::move * remove lock * put counter after create_packet_out * put counter after send_packet_out * use marl to send packet out * added marl code to BaseOFConnection::send * Disabled marl scheduling for OFConnection * try to send flow_mod when receiving a packet_in * enabled send packet out again, and test if cbench's OFPT_VENDOR should also count * use marl to send flow_mod * test parse_packet with marl * Bring back gRPC client/server for testing * Reverted OF version from 1.0 to 1.3 * comment out set ports' vlan tag for testing * bring back adding getting ovs connections with bridge name * added logs to investigate why no ovs flows are set up * modified of message version * commented out logs and time calculations to speed up the gs processing * Try to use marl to update neighbor states * Try to use marl to manage the whole gRPC server, so that update neighbor state can use marl, too * Added waitGroup.wait() * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Check what should be the size of the wait group * Use neighbor_count as waitGroup count; also changed back to for each loop when updating neighbor states * try not to use defer() * add one in waitgroup when iter through 1 neighbor * Try to use barrier request/reply to check neighbor procecssing time * added endl to printout * Try to send barrier request at the 950k th neighbor creation * Changed to send barrier request at the 970k th neighbor creation * try to use marl to furthur schedule create l2 neighbor * try to use marl to schedule execute_openflow when create_l2_neighbor * comment out duplicated part * comment out duplicated part * comment out extra code * revert back changes * enable counter again * put second counter after assert revision number * put second counter after invalid argument checks * increment first counter before marl schedule * put second counter at the beginning of update_neighbor_state_workitem * Improve performance by reducing unnecessary syslogs * Use marl::schedule to process netowrk resource states * added waitgroup to marl::schedule * added marl::schedule to on-demand engine * bring back original _parse_arp_request, in order to test with NCM * add changes from #272 * Reverted ACA_ARP_Responder::_serialize_arp_message * Cleaned up code * Cleaned up more code * Changed multiple logs from INFO to DEBUG * Add marl dependencies in cmake as well as machine init script * Fix marl dependency location in test cmake * Fix docker file marl dependency * Fix spaces * removed fmt library related code * corrected comment about OpenFlow Version * Tried to fix the memory leak * fixed blank lines and identation * Always restart AlcorControlAgent with new build, and set default debug flag to false in aca-machine-init Co-authored-by: Longzhang Fu --- alcor | 2 +- build/Dockerfile | 11 + build/aca-machine-init.sh | 27 ++- include/aca_on_demand_engine.h | 29 ++- include/libfluid-base/base/EventLoop.hh | 6 +- include/of_controller.h | 14 +- src/CMakeLists.txt | 2 + src/aca_main.cpp | 30 ++- src/comm/aca_grpc.cpp | 20 +- src/dp_abstraction/aca_dataplane_ovs.cpp | 20 +- src/dp_abstraction/aca_goal_state_handler.cpp | 214 ++++++------------ src/on_demand/aca_on_demand_engine.cpp | 35 +-- src/ovs/aca_arp_responder.cpp | 7 +- src/ovs/aca_ovs_l2_programmer.cpp | 13 +- src/ovs/libfluid-base/OFConnection.cc | 3 +- src/ovs/libfluid-base/base/BaseOFClient.cc | 15 +- src/ovs/libfluid-base/base/BaseOFServer.cc | 20 +- src/ovs/libfluid-base/base/EventLoop.cc | 9 +- src/ovs/of_controller.cpp | 28 +-- src/ovs/of_message.cpp | 1 + src/ovs/ovs_control.cpp | 10 +- test/CMakeLists.txt | 2 + test/func_tests/gs_tests.cpp | 1 + test/gtest/aca_test_arp.cpp | 2 +- test/gtest/aca_test_dhcp.cpp | 2 +- test/gtest/aca_test_oam.cpp | 2 +- test/gtest/aca_test_zeta_programming.cpp | 2 +- 27 files changed, 272 insertions(+), 255 deletions(-) diff --git a/alcor b/alcor index 97fc7b84..f3fd109c 160000 --- a/alcor +++ b/alcor @@ -1 +1 @@ -Subproject commit 97fc7b8482320f121889dd4211f71b29a77d6275 +Subproject commit f3fd109c65b6b80a960ef4aabb743f8a92788047 diff --git a/build/Dockerfile b/build/Dockerfile index 8c1c7195..49721e86 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -194,3 +194,14 @@ RUN echo "6--- installing pulsar dependacies ---" && \ apt install -y ./apache-pulsar-client*.deb && \ rm -rf /var/local/git/pulsar +RUN echo "7--- installing marl ---" && \ + mkdir -p /var/local/git/marl && \ + cd /var/local/git/marl && \ + git clone https://github.com/google/marl.git && \ + cd /var/local/git/marl/marl && \ + git submodule update --init && \ + mkdir /var/local/git/marl/marl/build && \ + cd /var/local/git/marl/marl/build && \ + cmake .. -DMARL_BUILD_EXAMPLES=1 -DMARL_BUILD_TESTS=1 && \ + make && \ + cd ~ \ No newline at end of file diff --git a/build/aca-machine-init.sh b/build/aca-machine-init.sh index 8ac558a5..78153ff4 100755 --- a/build/aca-machine-init.sh +++ b/build/aca-machine-init.sh @@ -199,8 +199,20 @@ echo "6--- installing openvswitch dependancies ---" && \ test -f /usr/bin/ovs-vsctl && rm -rf /usr/local/sbin/ov* /usr/local/bin/ov* /usr/local/bin/vtep* && \ cd ~ +echo "7--- installing marl ---" && \ + mkdir -p /var/local/git/marl && \ + cd /var/local/git/marl && \ + git clone https://github.com/google/marl.git && \ + cd /var/local/git/marl/marl && \ + git submodule update --init && \ + mkdir /var/local/git/marl/marl/build && \ + cd /var/local/git/marl/marl/build && \ + cmake .. -DMARL_BUILD_EXAMPLES=1 -DMARL_BUILD_TESTS=1 && \ + make && \ + cd ~ + PULSAR_RELEASE_TAG='pulsar-2.8.1' -echo "7--- installing pulsar dependacies ---" && \ +echo "8--- installing pulsar dependacies ---" && \ mkdir -p /var/local/git/pulsar && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client.deb -O /var/local/git/pulsar/apache-pulsar-client.deb && \ wget https://archive.apache.org/dist/pulsar/${PULSAR_RELEASE_TAG}/DEB/apache-pulsar-client-dev.deb -O /var/local/git/pulsar/apache-pulsar-client-dev.deb && \ @@ -209,7 +221,7 @@ echo "7--- installing pulsar dependacies ---" && \ rm -rf /var/local/git/pulsar cd ~ -echo "8--- building alcor-control-agent" +echo "9--- building alcor-control-agent" cd $BUILD/.. && cmake . && \ # after cmake ., modify the generated link.txt s so that the "-lssl" and "-lcrypto" appears after the openvswitch, so that it can compile sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' src/CMakeFiles/AlcorControlAgent.dir/link.txt && \ @@ -217,12 +229,15 @@ sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/aca_te sed -i 's/\(-ldl -lrt -lm -lpthread\)/-lssl -lcrypto \1/' test/CMakeFiles/gs_tests.dir/link.txt && \ make if [ -n "$1" -a "$1" = "delete-bridges" ]; then - echo "9--- deleting br-tun and br-int if requested" + echo "10--- deleting br-tun and br-int if requested" PATH=$PATH:/usr/local/share/openvswitch/scripts \ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib ovs-ctl --system-id=random --delete-bridges restart fi -echo "10--- running alcor-control-agent" -# sends output to null device, but stderr to console -nohup $BUILD/bin/AlcorControlAgent -d > /dev/null 2>&1 & +echo "11--- running alcor-control-agent" +# kill current AlcorControlAgent process if any +pkill -f AlcorControlAgent +# launch newly built AlcorControlAgent with default debug mode as 'false' +# sends output to null device, but stderr to console +nohup $BUILD/bin/AlcorControlAgent > /dev/null 2>&1 & diff --git a/include/aca_on_demand_engine.h b/include/aca_on_demand_engine.h index 2629826f..3f6020f0 100644 --- a/include/aca_on_demand_engine.h +++ b/include/aca_on_demand_engine.h @@ -20,9 +20,8 @@ #define STDOUT_FILENO 1 /* Standard output. */ #include "common.pb.h" -#include -//#include -#include +#include "libfluid-msg/of10msg.hh" +#include "libfluid-msg/of13msg.hh" #include #include #include @@ -31,11 +30,14 @@ #include #include "aca_log.h" #include "goalstateprovisioner.grpc.pb.h" -#include "ctpl/ctpl_stl.h" + +#include "marl/defer.h" +#include "marl/event.h" +#include "marl/scheduler.h" +#include "marl/waitgroup.h" using namespace alcor::schema; using namespace std; -using namespace ctpl; extern int thread_pools_size; @@ -74,8 +76,6 @@ class ACA_On_Demand_Engine { its initial value should be the time when clean_remaining_payload() was first called*/ std::chrono::_V2::steady_clock::time_point last_time_cleaned_remaining_payload; - ctpl::thread_pool thread_pool_; - static ACA_On_Demand_Engine &get_instance(); /* @@ -175,14 +175,12 @@ class ACA_On_Demand_Engine { int cores = std::thread::hardware_concurrency(); ACA_LOG_DEBUG("This host has %ld cores, setting the size of the thread pools to be %ld\n", cores, thread_pools_size); - on_demand_reply_processing_thread = new std::thread( - std::bind(&ACA_On_Demand_Engine::process_async_grpc_replies, this)); - - on_demand_reply_processing_thread->detach(); - on_demand_payload_cleaning_thread = new std::thread( - std::bind(&ACA_On_Demand_Engine::clean_remaining_payload, this)); - on_demand_payload_cleaning_thread->detach(); - thread_pool_.resize(thread_pools_size); + marl::schedule([=]{ + process_async_grpc_replies(); + }); + marl::schedule([=]{ + clean_remaining_payload(); + }); }; ~ACA_On_Demand_Engine() { @@ -190,7 +188,6 @@ class ACA_On_Demand_Engine { request_uuid_on_demand_payload_map.clear(); delete on_demand_reply_processing_thread; delete on_demand_payload_cleaning_thread; - thread_pool_.stop(); }; }; } // namespace aca_on_demand_engine diff --git a/include/libfluid-base/base/EventLoop.hh b/include/libfluid-base/base/EventLoop.hh index 8b8e9eb4..a089603e 100644 --- a/include/libfluid-base/base/EventLoop.hh +++ b/include/libfluid-base/base/EventLoop.hh @@ -17,6 +17,9 @@ #ifndef __EVENTLOOP_HH__ #define __EVENTLOOP_HH__ +#include "marl/defer.h" +#include "marl/scheduler.h" + namespace fluid_base { class BaseOFServer; @@ -41,7 +44,7 @@ public: @param id event loop id */ - EventLoop(int id); + EventLoop(int id, marl::Scheduler* scheduler); ~EventLoop(); /** @@ -80,6 +83,7 @@ private: class LibEventEventLoop; friend class LibEventEventLoop; LibEventEventLoop* m_implementation; + marl::Scheduler* m_scheduler; }; } diff --git a/include/of_controller.h b/include/of_controller.h index 3e91bc77..f86f7de3 100644 --- a/include/of_controller.h +++ b/include/of_controller.h @@ -25,6 +25,11 @@ #include "libfluid-msg/of10msg.hh" #include "libfluid-msg/of13msg.hh" +#include "marl/defer.h" +#include "marl/event.h" +#include "marl/scheduler.h" +#include "marl/waitgroup.h" + #include #include #include @@ -40,6 +45,8 @@ #include #include #include +#include + using namespace fluid_base; using namespace fluid_msg; @@ -56,8 +63,10 @@ class OFController : public OFServer { switch_dpid_map(switch_dpid_map), port_id_map(port_id_map), OFServer(address, port, nthreads, secure, - OFServerSettings().supported_version(4) // OF version 0x04 is OF 1.3 - .echo_interval(30)) { } + OFServerSettings() + .supported_version(4) // OF version 1 is OF 1.0 and version 4 is 1.3 + .echo_interval(30)) { + } ~OFController() = default; @@ -86,6 +95,7 @@ class OFController : public OFServer { void packet_out(const char* br, const char* opt); private: + // tracking xid (ovs transaction id) std::atomic xid; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a0f4992..8f988f7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,12 +66,14 @@ link_libraries(/usr/lib/x86_64-linux-gnu/libuuid.so) link_libraries(/usr/lib/x86_64-linux-gnu/libevent_pthreads.so) link_libraries(/usr/lib/x86_64-linux-gnu/libpthread.so) link_libraries(/usr/local/lib/libopenvswitch.a) #this was installed by aca-machine-init.sh +link_libraries(/var/local/git/marl/marl/build/libmarl.a) #this was built by aca-machine-init.sh include_directories(${RDKAFKA_INCLUDE_DIR} ${CPPKAFKA_INCLUDE_DIR} ${PULSAR_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/proto3) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/grpc) include_directories(/usr/local/include/openvswitch) include_directories(/usr/local/include/openflow) +include_directories(/var/local/git/marl/marl/include) # Find Protobuf installation # Looks for protobuf-config.cmake file installed by Protobuf's cmake installation. diff --git a/src/aca_main.cpp b/src/aca_main.cpp index 8e4b52fe..e064e549 100644 --- a/src/aca_main.cpp +++ b/src/aca_main.cpp @@ -35,6 +35,11 @@ #include #include +#include "marl/defer.h" +#include "marl/event.h" +#include "marl/scheduler.h" +#include "marl/waitgroup.h" + using aca_message_pulsar::ACA_Message_Pulsar_Consumer; using aca_ovs_control::ACA_OVS_Control; using std::string; @@ -240,6 +245,7 @@ int main(int argc, char *argv[]) } } + // fill in the information if not provided in command line args if (g_broker_list == EMPTY_STRING) { g_broker_list = BROKER_LIST; @@ -261,15 +267,25 @@ int main(int argc, char *argv[]) } g_grpc_server = new GoalStateProvisionerAsyncServer(); - g_grpc_server_thread = new std::thread(std::bind( - &GoalStateProvisionerAsyncServer::RunServer, g_grpc_server, thread_pools_size)); - g_grpc_server_thread->detach(); - + // Create a separate thread to run the grpc client. g_grpc_client = new GoalStateProvisionerClientImpl(); - g_grpc_client_thread = new std::thread( - std::bind(&GoalStateProvisionerClientImpl::RunClient, g_grpc_client)); - g_grpc_client_thread->detach(); + + // Create a marl scheduler using all the logical processors available to the process. + // Bind this scheduler to the main thread so we can call marl::schedule() + marl::Scheduler::Config cfg_bind_hw_cores; + cfg_bind_hw_cores.setWorkerThreadCount(thread_pools_size * 2); + marl::Scheduler task_scheduler(cfg_bind_hw_cores); + task_scheduler.bind(); + defer(task_scheduler.unbind()); + + marl::schedule([=]{ + g_grpc_server->RunServer(thread_pools_size); + }); + + marl::schedule([=]{ + g_grpc_client->RunClient(); + }); aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().get_local_host_ips(); diff --git a/src/comm/aca_grpc.cpp b/src/comm/aca_grpc.cpp index 4c4c06cd..f06e3197 100644 --- a/src/comm/aca_grpc.cpp +++ b/src/comm/aca_grpc.cpp @@ -31,6 +31,11 @@ #include "aca_log.h" #include "aca_grpc.h" +#include "marl/defer.h" +#include "marl/event.h" +#include "marl/scheduler.h" +#include "marl/waitgroup.h" + extern string g_grpc_server_port; extern string g_ncm_address; extern string g_ncm_port; @@ -43,7 +48,6 @@ Status GoalStateProvisionerAsyncServer::ShutDownServer() ACA_LOG_INFO("%s", "Shutdown server"); server_->Shutdown(); cq_->Shutdown(); - thread_pool_.stop(); keepReadingFromCq_ = false; return Status::OK; } @@ -275,15 +279,7 @@ void GoalStateProvisionerAsyncServer::AsyncWorkder() void GoalStateProvisionerAsyncServer::RunServer(int thread_pool_size) { ACA_LOG_INFO("Start of RunServer, pool size %ld\n", thread_pool_size); - - thread_pool_.resize(thread_pool_size); - ACA_LOG_DEBUG("Async GRPC SERVER: Resized thread pool to %ld threads, start waiting for the pool to have enough threads\n", - thread_pool_size); - /* wait for thread pool to initialize*/ - while (thread_pool_.n_idle() != thread_pool_.size()) { - ACA_LOG_DEBUG("%s\n", "Still waiting...sleep 1 ms"); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - }; + ACA_LOG_DEBUG("Async GRPC SERVER: finised resizing thread pool to %ld threads\n", thread_pool_size); // Create the server @@ -331,6 +327,8 @@ void GoalStateProvisionerAsyncServer::RunServer(int thread_pool_size) for (int i = 0; i < thread_pool_size; i++) { ACA_LOG_DEBUG("Pushing the %ldth async worker into the pool", i); - thread_pool_.push(std::bind(&GoalStateProvisionerAsyncServer::AsyncWorkder, this)); + marl::schedule([=]{ + AsyncWorkder(); + }); } } diff --git a/src/dp_abstraction/aca_dataplane_ovs.cpp b/src/dp_abstraction/aca_dataplane_ovs.cpp index ba27a27b..da00763f 100644 --- a/src/dp_abstraction/aca_dataplane_ovs.cpp +++ b/src/dp_abstraction/aca_dataplane_ovs.cpp @@ -329,9 +329,9 @@ int ACA_Dataplane_OVS::update_port_state_workitem(const PortState current_PortSt culminative_network_configuration_time, operation_total_time); if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the port state.\n"); + ACA_LOG_DEBUG("%s", "Successfully configured the port state.\n"); } else if (overall_rc == EINPROGRESS) { - ACA_LOG_INFO("Port state returned pending: rc=%d\n", overall_rc); + ACA_LOG_DEBUG("Port state returned pending: rc=%d\n", overall_rc); } else { ACA_LOG_ERROR("Unable to configure the port state: rc=%d\n", overall_rc); } @@ -541,9 +541,9 @@ int ACA_Dataplane_OVS::update_port_state_workitem(const PortState current_PortSt culminative_network_configuration_time, operation_total_time); if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the port state.\n"); + ACA_LOG_DEBUG("%s", "Successfully configured the port state.\n"); } else if (overall_rc == EINPROGRESS) { - ACA_LOG_INFO("Port state returned pending: rc=%d\n", overall_rc); + ACA_LOG_DEBUG("Port state returned pending: rc=%d\n", overall_rc); } else { ACA_LOG_ERROR("Unable to configure the port state: rc=%d\n", overall_rc); } @@ -730,9 +730,7 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig overall_rc, culminative_dataplane_programming_time, culminative_network_configuration_time, operation_total_time); - if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the neighbor state.\n"); - } else { + if (overall_rc != EXIT_SUCCESS) { ACA_LOG_ERROR("Unable to configure the neighbor state: rc=%d\n", overall_rc); } @@ -907,9 +905,7 @@ int ACA_Dataplane_OVS::update_neighbor_state_workitem(NeighborState current_Neig overall_rc = -EFAULT; } - if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the neighbor state.\n"); - } else { + if (overall_rc != EXIT_SUCCESS) { ACA_LOG_ERROR("Unable to configure the neighbor state: rc=%d\n", overall_rc); } @@ -965,7 +961,7 @@ int ACA_Dataplane_OVS::update_router_state_workitem(RouterState current_RouterSt culminative_network_configuration_time, operation_total_time); if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the router state.\n"); + ACA_LOG_DEBUG("%s", "Successfully configured the router state.\n"); } else { ACA_LOG_ERROR("Unable to configure the router state: rc=%d\n", overall_rc); } @@ -1022,7 +1018,7 @@ int ACA_Dataplane_OVS::update_router_state_workitem(RouterState current_RouterSt culminative_network_configuration_time, operation_total_time); if (overall_rc == EXIT_SUCCESS) { - ACA_LOG_INFO("%s", "Successfully configured the router state.\n"); + ACA_LOG_DEBUG("%s", "Successfully configured the router state.\n"); } else { ACA_LOG_ERROR("Unable to configure the router state: rc=%d\n", overall_rc); } diff --git a/src/dp_abstraction/aca_goal_state_handler.cpp b/src/dp_abstraction/aca_goal_state_handler.cpp index 81b72351..bfcc5660 100644 --- a/src/dp_abstraction/aca_goal_state_handler.cpp +++ b/src/dp_abstraction/aca_goal_state_handler.cpp @@ -16,8 +16,14 @@ #include "aca_dataplane_ovs.h" #include "aca_goal_state_handler.h" #include "goalstateprovisioner.grpc.pb.h" +#include "aca_ovs_l2_programmer.h" #include +#include "marl/defer.h" +#include "marl/event.h" +#include "marl/scheduler.h" +#include "marl/waitgroup.h" + using namespace alcor::schema; std::mutex gs_reply_mutex; // mutex for writing gs reply object @@ -136,41 +142,24 @@ int Aca_Goal_State_Handler::update_port_state_workitem(const PortState current_P int Aca_Goal_State_Handler::update_port_states(GoalState &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; - + GoalState* gs_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.port_states_size()); for (int i = 0; i < parsed_struct.port_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing port states #%d\n", i); PortState current_PortState = parsed_struct.port_states(i); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_port_state_workitem, this, - current_PortState, std::ref(parsed_struct), std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0){ - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - workitem_future.clear(); - count = 1; - } else { - count ++; - } - // keeping below just in case if we want to call it serially - // rc = update_port_state_workitem(current_PortState, parsed_struct, gsOperationReply); - // if (rc != EXIT_SUCCESS) - // overall_rc = rc; - } // for (int i = 0; i < parsed_struct.port_states_size(); i++) - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } // for (int i = 0; i < parsed_struct.port_states_size(); i++) + + marl::schedule([=] { + defer(wait_group.done()); + update_port_state_workitem(current_PortState, *gs_ptr, *reply_ptr); + }); + + } + wait_group.wait(); return overall_rc; } @@ -188,40 +177,23 @@ int Aca_Goal_State_Handler::update_port_state_workitem_v2(const PortState curren int Aca_Goal_State_Handler::update_port_states(GoalStateV2 &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; + GoalStateV2* gsv2_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.port_states_size()); + // below is a c++ 17 feature for (auto &[port_id, current_PortState] : parsed_struct.port_states()) { ACA_LOG_DEBUG("=====>parsing port state: %s\n", port_id.c_str()); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_port_state_workitem_v2, this, - current_PortState, std::ref(parsed_struct), std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0) { - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - workitem_future.clear(); - count = 1; - } else { - count ++; - } - // keeping below just in case if we want to call it serially - // rc = update_port_state_workitem(current_PortState, parsed_struct, gsOperationReply); - // if (rc != EXIT_SUCCESS) - // overall_rc = rc; - } // for (int i = 0; i < parsed_struct.port_states_size(); i++) - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } // for (int i = 0; i < parsed_struct.port_states_size(); i++) - + marl::schedule([=] { + defer(wait_group.done()); + update_port_state_workitem_v2(current_PortState, *gsv2_ptr, *reply_ptr); + }); + } + wait_group.wait(); + return overall_rc; } @@ -236,39 +208,24 @@ int Aca_Goal_State_Handler::update_neighbor_state_workitem(const NeighborState c int Aca_Goal_State_Handler::update_neighbor_states(GoalState &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; + GoalState* gs_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.neighbor_states_size()); for (int i = 0; i < parsed_struct.neighbor_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing neighbor states #%d\n", i); NeighborState current_NeighborState = parsed_struct.neighbor_states(i); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_neighbor_state_workitem, - this, current_NeighborState, std::ref(parsed_struct), - std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0) { - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - workitem_future.clear(); - count = 1; - } else { - count ++; - } + marl::schedule([=] { + defer(wait_group.done()); + update_neighbor_state_workitem(current_NeighborState, *gs_ptr, *reply_ptr); + }); } - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - + wait_group.wait(); + return overall_rc; } @@ -283,37 +240,23 @@ int Aca_Goal_State_Handler::update_router_state_workitem(const RouterState curre int Aca_Goal_State_Handler::update_router_states(GoalState &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; + GoalState* gs_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.router_states_size()); for (int i = 0; i < parsed_struct.router_states_size(); i++) { ACA_LOG_DEBUG("=====>parsing router states #%d\n", i); RouterState current_RouterState = parsed_struct.router_states(i); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_router_state_workitem, this, - current_RouterState, std::ref(parsed_struct), std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0) { - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - workitem_future.clear(); - count = 1; - } else { - count ++; - } - } - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; + marl::schedule([=] { + defer(wait_group.done()); + update_router_state_workitem(current_RouterState, *gs_ptr, *reply_ptr); + }); } + wait_group.wait(); return overall_rc; } @@ -329,38 +272,21 @@ int Aca_Goal_State_Handler::update_neighbor_state_workitem_v2( int Aca_Goal_State_Handler::update_neighbor_states(GoalStateV2 &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; - + GoalStateV2* gsv2_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.neighbor_states_size()); + for (auto &[neighbor_id, current_NeighborState] : parsed_struct.neighbor_states()) { - ACA_LOG_DEBUG("=====>parsing neighbor state: %s\n", neighbor_id.c_str()); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_neighbor_state_workitem_v2, - this, current_NeighborState, std::ref(parsed_struct), - std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0) { - for (int i = 0 ; i < workitem_future.size(); i++){ - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS){ - overall_rc = rc; - } - } - workitem_future.clear(); - count = 1; - } else { - count++; - } - } - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; + marl::schedule([=] { + defer(wait_group.done()); + update_neighbor_state_workitem_v2(current_NeighborState, *gsv2_ptr, *reply_ptr); + }); } - + wait_group.wait(); + return overall_rc; } @@ -375,35 +301,21 @@ int Aca_Goal_State_Handler::update_router_state_workitem_v2(const RouterState cu int Aca_Goal_State_Handler::update_router_states(GoalStateV2 &parsed_struct, GoalStateOperationReply &gsOperationReply) { - std::vector > workitem_future; int rc; int overall_rc = EXIT_SUCCESS; int count = 1; + GoalStateV2* gsv2_ptr = &parsed_struct; + GoalStateOperationReply* reply_ptr = &gsOperationReply; + marl::WaitGroup wait_group(parsed_struct.router_states_size()); for (auto &[router_id, current_RouterState] : parsed_struct.router_states()) { ACA_LOG_DEBUG("=====>parsing router state: %s\n", router_id.c_str()); - - workitem_future.push_back(std::async( - std::launch::async, &Aca_Goal_State_Handler::update_router_state_workitem_v2, this, - current_RouterState, std::ref(parsed_struct), std::ref(gsOperationReply))); - if (count % resource_state_processing_batch_size == 0){ - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; - } - workitem_future.clear(); - count = 1; - } else { - count ++; - } - } - - for (int i = 0; i < workitem_future.size(); i++) { - rc = workitem_future[i].get(); - if (rc != EXIT_SUCCESS) - overall_rc = rc; + marl::schedule([=] { + defer(wait_group.done()); + update_router_state_workitem_v2(current_RouterState, *gsv2_ptr, *reply_ptr); + }); } + wait_group.wait(); return overall_rc; } diff --git a/src/on_demand/aca_on_demand_engine.cpp b/src/on_demand/aca_on_demand_engine.cpp index 7c53e8ef..e33d5e53 100644 --- a/src/on_demand/aca_on_demand_engine.cpp +++ b/src/on_demand/aca_on_demand_engine.cpp @@ -46,6 +46,9 @@ #undef ARRAY_SIZE #undef ROUND_UP #include "aca_on_demand_engine.h" +#include +//#include +#include using namespace std; using namespace aca_vlan_manager; @@ -57,6 +60,7 @@ extern bool g_demo_mode; extern string g_ncm_address, g_ncm_port; extern GoalStateProvisionerClientImpl *g_grpc_client; + namespace aca_on_demand_engine { ACA_On_Demand_Engine &ACA_On_Demand_Engine::get_instance() @@ -197,13 +201,12 @@ void ACA_On_Demand_Engine::process_async_grpc_replies() to_string(replyStatus).c_str()); ACA_LOG_DEBUG("Received hostOperationReply in thread id: [%ld]\n", std::this_thread::get_id()); - thread_pool_.push(std::bind(&ACA_On_Demand_Engine::process_async_replies_asyncly, this, - request_id, replyStatus, received_ncm_reply_time)); - ACA_LOG_DEBUG("After using the thread pool, we have %ld idle threads in the pool, thread pool size: %ld\n", - thread_pool_.n_idle(), thread_pool_.size()); + marl::schedule([=]{ + process_async_replies_asyncly(request_id, replyStatus, received_ncm_reply_time); + }); } } else { - ACA_LOG_INFO("%s\n", "Got an GRPC reply that is NOT OK, don't need to process the data"); + ACA_LOG_DEBUG("%s\n", "Got an GRPC reply that is NOT OK, don't need to process the data"); } } } @@ -228,7 +231,7 @@ void ACA_On_Demand_Engine::unknown_recv(uint16_t vlan_id, string ip_src, new_state_requests->set_ethertype(EtherType::IPV4); std::chrono::_V2::steady_clock::time_point call_ncm_time = std::chrono::steady_clock::now(); - ACA_LOG_DEBUG("For UUID: [%s], calling NCM for info of IP [%s] at: [%ld], tunnel_id: []\n", + ACA_LOG_DEBUG("For UUID: [%s], calling NCM for info of IP [%s] at: [%ld], tunnel_id: [%ld]\n", uuid_str, ip_dest.c_str(), call_ncm_time, tunnel_id); std::chrono::_V2::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); @@ -244,7 +247,7 @@ void ACA_On_Demand_Engine::on_demand(string uuid_for_call, OperationStatus statu int packet_size, Protocol protocol, std::chrono::_V2::steady_clock::time_point insert_time) { - ACA_LOG_INFO("%s\n", "Inside of on_demand function"); + ACA_LOG_DEBUG("%s\n", "Inside of on_demand function"); string bridge = "br-tun"; string inport = "in_port=controller"; string whitespace = " "; @@ -345,14 +348,15 @@ void ACA_On_Demand_Engine::on_demand(string uuid_for_call, OperationStatus statu void ACA_On_Demand_Engine::parse_packet(uint32_t in_port, void *packet) { + const struct ether_header *eth_header; /* The packet is larger than the ether_header struct, - but we just want to look at the first part of the packet - that contains the header. We force the compiler - to treat the pointer to the packet as just a pointer - to the ether_header. The data payload of the packet comes - after the headers. Different packet types have different header - lengths though, but the ethernet header is always the same (14 bytes) */ + but we just want to look at the first part of the packet + that contains the header. We force the compiler + to treat the pointer to the packet as just a pointer + to the ether_header. The data payload of the packet comes + after the headers. Different packet types have different header + lengths though, but the ethernet header is always the same (14 bytes) */ eth_header = (struct ether_header *)packet; ACA_LOG_DEBUG("Source Mac: %s\n", ether_ntoa((ether_addr *)ð_header->ether_shost)); @@ -367,8 +371,10 @@ void ACA_On_Demand_Engine::parse_packet(uint32_t in_port, void *packet) Protocol _protocol = Protocol::Protocol_INT_MAX_SENTINEL_DO_NOT_USE_; uint16_t ether_type = ntohs(*(uint16_t *)(base + 12)); + if (ether_type == ETHERTYPE_VLAN) { - ACA_LOG_INFO("%s", "Ethernet Type: 802.1Q VLAN tagging (0x8100) \n"); + ACA_LOG_DEBUG("%s", "Ethernet Type: 802.1Q VLAN tagging (0x8100) \n"); + ether_type = ntohs(*(uint16_t *)(base + 16)); vlan_len = 4; vlan_hdr = (unsigned char *)(base + 12); @@ -380,6 +386,7 @@ void ACA_On_Demand_Engine::parse_packet(uint32_t in_port, void *packet) } if (ether_type == ETHERTYPE_ARP) { + ACA_LOG_DEBUG("%s", "Ethernet Type: ARP (0x0806) \n"); ACA_LOG_DEBUG(" From: %s\n", inet_ntoa(*(in_addr *)(base + 14 + vlan_len + 14))); ACA_LOG_DEBUG(" to: %s\n", diff --git a/src/ovs/aca_arp_responder.cpp b/src/ovs/aca_arp_responder.cpp index f2a2b4ae..81879139 100644 --- a/src/ovs/aca_arp_responder.cpp +++ b/src/ovs/aca_arp_responder.cpp @@ -22,6 +22,7 @@ #include #include + using namespace std; namespace aca_arp_responder @@ -249,6 +250,7 @@ void ACA_ARP_Responder::arp_xmit(uint32_t in_port, void *vlanmsg, void *message, ACA_LOG_ERROR("%s", "Serialized ARP Reply is null!\n"); return; } + if (is_found) { options = inport + whitespace + packetpre + packet + whitespace + action; //delete the constructed arp reply @@ -258,8 +260,7 @@ void ACA_ARP_Responder::arp_xmit(uint32_t in_port, void *vlanmsg, void *message, } ACA_LOG_DEBUG("ACA_ARP_Responder sent arp packet to ovs: %s\n", options.c_str()); - //aca_ovs_control::ACA_OVS_Control::get_instance().packet_out(bridge.c_str(), - // options.c_str()); + aca_ovs_l2_programmer::ACA_OVS_L2_Programmer::get_instance().packet_out(bridge.c_str(), options.c_str()); } @@ -280,7 +281,7 @@ int ACA_ARP_Responder::_parse_arp_request(uint32_t in_port, vlan_message *vlanms } else { stData.vlan_id = 0; } - + // if not find the corresponding mac address in the db based on ip and vlan id, resubmit to table 22 // else construct an arp reply if (!_arp_db.find(stData, current_arp_data)) { diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index f9bbb6cf..361a8f51 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -598,7 +597,7 @@ void ACA_OVS_L2_Programmer::execute_ovsdb_command(const std::string cmd_string, g_total_execute_ovsdb_time += ovsdb_client_time_total_time; - ACA_LOG_INFO("Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds. rc: %d, cmd: [%s]\n", + ACA_LOG_DEBUG("Elapsed time for ovsdb client call took: %ld microseconds or %ld milliseconds. rc: %d, cmd: [%s]\n", ovsdb_client_time_total_time, us_to_ms(ovsdb_client_time_total_time), rc, ovsdb_cmd_string.c_str()); @@ -628,7 +627,7 @@ void ACA_OVS_L2_Programmer::execute_openflow_command(const std::string cmd_strin g_total_execute_openflow_time += openflow_client_time_total_time; - ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds. rc: %d\n", + ACA_LOG_DEBUG("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds. rc: %d\n", openflow_client_time_total_time, us_to_ms(openflow_client_time_total_time), rc); @@ -657,9 +656,9 @@ void ACA_OVS_L2_Programmer::execute_openflow(ulong &culminative_time, g_total_execute_openflow_time += openflow_client_time_total_time; - // ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", - // openflow_client_time_total_time, - // us_to_ms(openflow_client_time_total_time)); + ACA_LOG_DEBUG("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + openflow_client_time_total_time, + us_to_ms(openflow_client_time_total_time)); ACA_LOG_DEBUG("%s", "ACA_OVS_L2_Programmer::execute_openflow ---> Exiting\n"); } @@ -681,7 +680,7 @@ void ACA_OVS_L2_Programmer::packet_out(const char *bridge, const char *options) g_total_execute_openflow_time += openflow_client_time_total_time; - ACA_LOG_INFO("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", + ACA_LOG_DEBUG("Elapsed time for openflow client call took: %ld microseconds or %ld milliseconds.\n", openflow_client_time_total_time, us_to_ms(openflow_client_time_total_time)); diff --git a/src/ovs/libfluid-base/OFConnection.cc b/src/ovs/libfluid-base/OFConnection.cc index 1239e441..35a72249 100644 --- a/src/ovs/libfluid-base/OFConnection.cc +++ b/src/ovs/libfluid-base/OFConnection.cc @@ -1,5 +1,6 @@ #include "libfluid-base/base/BaseOFConnection.hh" #include "libfluid-base/OFConnection.hh" +#include "libfluid-base/base/BaseOFConnection.hh" namespace fluid_base { @@ -53,7 +54,7 @@ OFHandler* OFConnection::get_ofhandler() { void OFConnection::send(void* data, size_t len) { if (this->conn != NULL) - this->conn->send((uint8_t*) data, len); + this->conn->send((uint8_t*) data, len); } void OFConnection::add_timed_callback(void* (*cb)(void*), diff --git a/src/ovs/libfluid-base/base/BaseOFClient.cc b/src/ovs/libfluid-base/base/BaseOFClient.cc index d29a68cf..0bd414f9 100644 --- a/src/ovs/libfluid-base/base/BaseOFClient.cc +++ b/src/ovs/libfluid-base/base/BaseOFClient.cc @@ -76,7 +76,20 @@ BaseOFClient::~BaseOFClient() { bool BaseOFClient::start(bool block) { this->blocking = block; - this->evloop = new EventLoop(0); + // Pass marl scheduler from main thread, where BaseOFClient/OFClient is called (in aca_main we don't use OFClient) + marl::Scheduler* scheduler = marl::Scheduler::get(); + int get_iteration = 0; + while (NULL == scheduler && get_iteration < 5) { + scheduler = marl::Scheduler::get(); + + if (NULL != scheduler) { + break; + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + get_iteration++; + } + } + this->evloop = new EventLoop(0, scheduler); // connect to ovs-db server and assign it to the event loop if (!this->connect()) { diff --git a/src/ovs/libfluid-base/base/BaseOFServer.cc b/src/ovs/libfluid-base/base/BaseOFServer.cc index 69e1944a..e0bf3605 100644 --- a/src/ovs/libfluid-base/base/BaseOFServer.cc +++ b/src/ovs/libfluid-base/base/BaseOFServer.cc @@ -18,6 +18,9 @@ #include #include +#include +#include +#include namespace fluid_base { @@ -67,9 +70,24 @@ BaseOFServer::BaseOFServer(const char* address_, const int port, const int nthre this->eventloops = new EventLoop*[nthreads]; this->threads = new pthread_t[nthreads]; memset(this->threads, 0, sizeof(pthread_t)*nthreads); + + // Pass marl scheduler from main thread, since BaseOFServer/OFServer/OFController init is only called on main thread (by aca_main) + marl::Scheduler* scheduler = marl::Scheduler::get(); + int get_iteration = 0; + while (NULL == scheduler && get_iteration < 5) { + scheduler = marl::Scheduler::get(); + + if (NULL != scheduler) { + break; + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + get_iteration++; + } + } for (int i = 0; i < nthreads; i++) { - this->eventloops[i] = new EventLoop(i); + this->eventloops[i] = new EventLoop(i, scheduler); } + // The first event loop will be used for connections, so we move to the // next one for the first connection eventloop = 0; diff --git a/src/ovs/libfluid-base/base/EventLoop.cc b/src/ovs/libfluid-base/base/EventLoop.cc index f676781d..5fcf8b2b 100644 --- a/src/ovs/libfluid-base/base/EventLoop.cc +++ b/src/ovs/libfluid-base/base/EventLoop.cc @@ -17,12 +17,15 @@ class EventLoop::LibEventEventLoop { struct event_base *base; }; -EventLoop::EventLoop(int id) { +EventLoop::EventLoop(int id, marl::Scheduler* scheduler) { this->id = id; this->m_implementation = new EventLoop::LibEventEventLoop; this->m_implementation->base = event_base_new(); + // pass marl scheduler from main thread (OFController : OFServer initialization) + this->m_scheduler = scheduler; + this->stopped = false; if (!this->m_implementation->base) { fprintf(stderr, "Error creating EventLoop %d\n", id); @@ -53,6 +56,10 @@ void EventLoop::run() { // Only run if EventLoop::stop hasn't been called first if (stopped) return; + //// The m_scheduler is passed from main thread (OFController : OFServer construction), and then bind it in each new Eventloop pthread_create + m_scheduler->bind(); + defer(m_scheduler->unbind()); + event_base_dispatch(this->m_implementation->base); // See note in EventLoop::EventLoop. Here we disable the virtual event // to guarantee that nothing blocks. diff --git a/src/ovs/of_controller.cpp b/src/ovs/of_controller.cpp index b1ad302b..107525da 100644 --- a/src/ovs/of_controller.cpp +++ b/src/ovs/of_controller.cpp @@ -67,15 +67,15 @@ void OFController::message_callback(OFConnection* ofconn, uint8_t type, void* da auto t = std::chrono::high_resolution_clock::now(); ACA_LOG_INFO("OFController::message_callback - recv OFPT_BARRIER_REPLY on %ld\n", t.time_since_epoch().count()); } else if (type == fluid_msg::of13::OFPT_PACKET_IN) { - fluid_msg::of13::PacketIn *pin = new of13::PacketIn(); - pin->unpack((uint8_t *) data); + fluid_msg::of13::PacketIn *pin = new fluid_msg::of13::PacketIn(); + pin->unpack((uint8_t *)data); uint32_t in_port = pin->match().in_port()->value(); - - // pass new allocated memory of packet-in to ACA_On_Demand_Engine to determine which type of request it is - aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().thread_pool_.push( - std::bind(&aca_on_demand_engine::ACA_On_Demand_Engine::parse_packet, - &aca_on_demand_engine::ACA_On_Demand_Engine::get_instance(), - in_port, (void *)pin->data())); + marl::schedule([=] { + aca_on_demand_engine::ACA_On_Demand_Engine::get_instance().parse_packet( + in_port, + (void *)pin->data()); + delete pin; + }); } else if (type == 33) { // OFPRAW_OFPT14_BUNDLE_CONTROL auto t = std::chrono::high_resolution_clock::now(); @@ -131,18 +131,21 @@ void OFController::add_switch_to_conn_map(std::string bridge, int ofconn_id, OFC if (NULL != ofconn_iter->second) { // k is bridge name, v is OFConnection* ofconn_iter->second->close(); } + ACA_LOG_DEBUG("Removed ofconn_name: %s from switch_conn_map, when adding a new connection with the same name\n", bridge.c_str()); switch_conn_map.erase(bridge); } switch_conn_map[bridge] = ofconn; - + if (switch_id_map.find(ofconn_id) != switch_id_map.end()) { switch_id_map.erase(ofconn_id); } switch_id_map[ofconn_id] = bridge; + switch_map_mutex.unlock(); + ACA_LOG_INFO("OFController::add_switch_to_conn_map - ovs connection id=%d bridge=%s added to switch map\n", ofconn->get_id(), bridge.c_str()); } @@ -166,14 +169,13 @@ void OFController::remove_switch_from_conn_maps(std::string bridge, int ofconn_i } switch_conn_map.erase(bridge); } - + switch_map_mutex.unlock(); ACA_LOG_INFO("OFController::remove_switch_from_conn_map - ovs connection bridge=%s removed from switch map\n", bridge.c_str()); } - void OFController::remove_switch_from_conn_map(std::string bridge) { switch_map_mutex.lock(); auto ofconn_iter = switch_conn_map.find(bridge); @@ -217,7 +219,7 @@ void OFController::send_packet_out(OFConnection *ofconn, ofbuf_ptr_t &&po) { if (!po) { return; } - + ofconn->send(po->data(), po->len()); } @@ -304,4 +306,4 @@ void OFController::packet_out(const char* br, const char* opt) { } ofconn_br = NULL; -} \ No newline at end of file +} diff --git a/src/ovs/of_message.cpp b/src/ovs/of_message.cpp index 408b739f..250e03c1 100644 --- a/src/ovs/of_message.cpp +++ b/src/ovs/of_message.cpp @@ -28,6 +28,7 @@ #include #include + enum { ADD_FLOW = 0, MODIFY_FLOW = 1, diff --git a/src/ovs/ovs_control.cpp b/src/ovs/ovs_control.cpp index 8b529db0..0047332a 100644 --- a/src/ovs/ovs_control.cpp +++ b/src/ovs/ovs_control.cpp @@ -16,7 +16,11 @@ #include "aca_log.h" #include "aca_util.h" #include "ovs_control.h" -#include "aca_on_demand_engine.h" +#undef OFP_ASSERT +#undef CONTAINER_OF +#undef ARRAY_SIZE +#undef ROUND_UP +// #include "aca_on_demand_engine.h" #include // std::(istringstream) #include // std::(string) #include @@ -41,7 +45,7 @@ #include using namespace std; -using namespace aca_on_demand_engine; +// using namespace aca_on_demand_engine; extern std::atomic_ulong g_total_execute_openflow_time; @@ -1012,7 +1016,7 @@ void OVS_Control::monitor_vconn(vconn *vconn, bool reply_to_echo_requests, The pin.packet here has the same memory address, even after multiple calls. If you intent to store it somewhere, it is advised to make a copy of it. */ - ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); + // ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); if (error) { fprintf(stderr, "decoding packet-in failed: %s", diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5e9c4e4b..72e4518e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,7 +11,9 @@ FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../includ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/proto3) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/grpc) +include_directories(/var/local/git/marl/marl/include) link_libraries(${PULSAR}) +link_libraries(/var/local/git/marl/marl/build/libmarl.a) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/test/func_tests/gs_tests.cpp b/test/func_tests/gs_tests.cpp index 1b6a3bdf..9e4d80d3 100644 --- a/test/func_tests/gs_tests.cpp +++ b/test/func_tests/gs_tests.cpp @@ -79,6 +79,7 @@ std::atomic_ulong g_total_vpcs_table_mutex_time(0); std::atomic_ulong g_total_update_GS_time(0); // total time for ACA message in microseconds std::atomic_ulong g_total_ACA_Message_time(0); + bool g_demo_mode = false; bool g_debug_mode = false; diff --git a/test/gtest/aca_test_arp.cpp b/test/gtest/aca_test_arp.cpp index 4c1ded4f..72c4af02 100644 --- a/test/gtest/aca_test_arp.cpp +++ b/test/gtest/aca_test_arp.cpp @@ -13,10 +13,10 @@ // 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. #include "gtest/gtest.h" +#include "aca_ovs_l2_programmer.h" #define private public #include "aca_arp_responder.h" #include "aca_net_config.h" -#include "aca_ovs_l2_programmer.h" #include "aca_comm_mgr.h" #include "aca_util.h" #include "goalstate.pb.h" diff --git a/test/gtest/aca_test_dhcp.cpp b/test/gtest/aca_test_dhcp.cpp index eb487b77..8f0c9a6f 100644 --- a/test/gtest/aca_test_dhcp.cpp +++ b/test/gtest/aca_test_dhcp.cpp @@ -13,11 +13,11 @@ // 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. #include "gtest/gtest.h" +#include "aca_ovs_l2_programmer.h" #define private public #include "aca_dhcp_server.h" #include "aca_dhcp_programming_if.h" #include "aca_net_config.h" -#include "aca_ovs_l2_programmer.h" #include "aca_comm_mgr.h" #include "aca_util.h" #include "goalstate.pb.h" diff --git a/test/gtest/aca_test_oam.cpp b/test/gtest/aca_test_oam.cpp index ea7d8631..f7fdffb0 100644 --- a/test/gtest/aca_test_oam.cpp +++ b/test/gtest/aca_test_oam.cpp @@ -13,6 +13,7 @@ // 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. #include "gtest/gtest.h" +#include "aca_ovs_l2_programmer.h" #include "goalstateprovisioner.grpc.pb.h" #define private public #include "aca_zeta_oam_server.h" @@ -20,7 +21,6 @@ #include #include "aca_vlan_manager.h" #include "aca_zeta_programming.h" -#include "aca_ovs_l2_programmer.h" #undef OFP_ASSERT #undef CONTAINER_OF diff --git a/test/gtest/aca_test_zeta_programming.cpp b/test/gtest/aca_test_zeta_programming.cpp index 4bed2a97..8b216654 100644 --- a/test/gtest/aca_test_zeta_programming.cpp +++ b/test/gtest/aca_test_zeta_programming.cpp @@ -13,11 +13,11 @@ // 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. #include "gtest/gtest.h" +#include "aca_ovs_l2_programmer.h" #define private public #include "aca_util.h" #include "goalstateprovisioner.grpc.pb.h" #include -#include "aca_ovs_l2_programmer.h" #include "aca_comm_mgr.h" #include "aca_zeta_programming.h" #include "aca_util.h" From 0e7ee824b2a69097931cfbeadc249195b10ac7c9 Mon Sep 17 00:00:00 2001 From: lfu-ps <83976250+lfu-ps@users.noreply.github.com> Date: Thu, 27 Jan 2022 13:25:41 -0800 Subject: [PATCH 53/54] Add description of deprecated code path of ovs control, but also enable parse packet in it (#277) --- src/ovs/ovs_control.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ovs/ovs_control.cpp b/src/ovs/ovs_control.cpp index 0047332a..de573f5a 100644 --- a/src/ovs/ovs_control.cpp +++ b/src/ovs/ovs_control.cpp @@ -13,14 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. +/* + This file is legacy code path, that we used vconn from ovs code to connect and manipulate ovs by the same way of ovs cmd tools + From 9/30/2021 release, ovs connection and events/flows manipulation are already handled by of_controller.cpp + We leave this legacy file for reference + */ + #include "aca_log.h" #include "aca_util.h" -#include "ovs_control.h" +#include "aca_on_demand_engine.h" + #undef OFP_ASSERT #undef CONTAINER_OF #undef ARRAY_SIZE #undef ROUND_UP -// #include "aca_on_demand_engine.h" +#include "ovs_control.h" + #include // std::(istringstream) #include // std::(string) #include @@ -45,7 +53,7 @@ #include using namespace std; -// using namespace aca_on_demand_engine; +using namespace aca_on_demand_engine; extern std::atomic_ulong g_total_execute_openflow_time; @@ -1013,10 +1021,10 @@ void OVS_Control::monitor_vconn(vconn *vconn, bool reply_to_echo_requests, &buffer_idp, &continuation); uint32_t in_port = pin.flow_metadata.flow.in_port.ofp_port; /* - The pin.packet here has the same memory address, even after multiple calls. - If you intent to store it somewhere, it is advised to make a copy of it. - */ - // ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); + The pin.packet here has the same memory address, even after multiple calls. + If you intent to store it somewhere, it is advised to make a copy of it. + */ + ACA_On_Demand_Engine::get_instance().parse_packet(in_port, pin.packet); if (error) { fprintf(stderr, "decoding packet-in failed: %s", From c3108a7cdf3513fa15f6ada0ecb9f901c70fe50a Mon Sep 17 00:00:00 2001 From: Rio Zhu <32083634+zzxgzgz@users.noreply.github.com> Date: Tue, 1 Feb 2022 14:04:19 -0800 Subject: [PATCH 54/54] Routing rule gsv2 (#267) --- src/ovs/aca_ovs_l3_programmer.cpp | 88 +++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/ovs/aca_ovs_l3_programmer.cpp b/src/ovs/aca_ovs_l3_programmer.cpp index 5d7b37af..4042b7ee 100644 --- a/src/ovs/aca_ovs_l3_programmer.cpp +++ b/src/ovs/aca_ovs_l3_programmer.cpp @@ -829,6 +829,94 @@ int ACA_OVS_L3_Programmer::create_or_update_router(RouterConfiguration ¤t_ new_routing_rule_entry.next_hop_mac = current_routing_rule.routing_rule_extra_info().next_hop_mac(); + auto remote_host_ip = ""; + ulong culminative_dataplane_programming_time = 0; + for (auto each_neighbor : parsed_struct.neighbor_states()) { + NeighborConfiguration current_NeighborConfiguration1 = + each_neighbor.second.configuration(); + ACA_LOG_INFO("current_NeighborConfiguration.host_ip_address(): %s \n", + current_NeighborConfiguration1.host_ip_address().c_str()); + for (int y = 0; y < current_NeighborConfiguration1.fixed_ips_size(); y++) { + ACA_LOG_INFO("current_NeighborConfiguration.fixed_ips(%d): neighbor_type: %d, subnet_id %s, ip_address %s \n", + y, current_NeighborConfiguration1.fixed_ips(y).neighbor_type(), + current_NeighborConfiguration1.fixed_ips(y) + .subnet_id() + .c_str(), + current_NeighborConfiguration1.fixed_ips(y) + .ip_address() + .c_str()); + ACA_LOG_INFO("current_routing_rule.next_hop_ip() %s\n", + current_routing_rule.next_hop_ip().c_str()); + auto current_fixed_ip = current_NeighborConfiguration1.fixed_ips(y); + string virtual_ip_address = current_fixed_ip.ip_address(); + string virtual_mac_address = + current_NeighborConfiguration1.mac_address(); + string subnet_id_of_fixed_ip = current_fixed_ip.subnet_id(); + string gw_mac; + uint dest_tunnel_id = 0; + + if (strcmp(current_routing_rule.next_hop_ip().c_str(), + current_fixed_ip.ip_address().c_str()) == 0) { + auto subnet_iterator = parsed_struct.subnet_states().find(subnet_id_of_fixed_ip); + if (subnet_iterator != parsed_struct.subnet_states().end()) { + gw_mac = subnet_iterator->second.configuration().gateway().mac_address(); + dest_tunnel_id = subnet_iterator->second.configuration().tunnel_id(); + ACA_LOG_INFO("gw_mac: %s\n", gw_mac.c_str()); + ACA_LOG_INFO("dest_tunnel_id: %d\n", dest_tunnel_id); + } else { + ACA_LOG_INFO("Founding find subnet ID: [%s] in the goalstate", subnet_id_of_fixed_ip); + } + + remote_host_ip = + current_NeighborConfiguration1.host_ip_address().c_str(); + int source_vlan_id = + ACA_Vlan_Manager::get_instance().get_or_create_vlan_id(found_tunnel_id); + + int destination_vlan_id = + ACA_Vlan_Manager::get_instance().get_or_create_vlan_id(dest_tunnel_id); + + bool is_port_on_same_host = + ACA_OVS_L2_Programmer::get_instance().is_ip_on_the_same_host(remote_host_ip); + + ACA_LOG_INFO("current_fixed_ip.subnet_id(): %s\n", + current_fixed_ip.subnet_id().c_str()); + ACA_LOG_INFO("current_subnet_routing_table.subnet_id(): %s\n", + current_subnet_routing_table.subnet_id().c_str()); + + if (is_port_on_same_host) { + if (current_fixed_ip.subnet_id() != + current_subnet_routing_table.subnet_id()) { + cmd_string = + "table=0,priority=50,ip,dl_vlan=" + + to_string(source_vlan_id) + + ",nw_dst=" + current_routing_rule.destination() + + ",dl_dst=" + found_gateway_mac + + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + + ",mod_dl_src:" + gw_mac + + ",mod_dl_dst:" + virtual_mac_address + ",output:IN_PORT"; + } + } else { + cmd_string = + "table=0,priority=50,ip,dl_vlan=" + + to_string(source_vlan_id) + + ",nw_dst=" + current_routing_rule.destination() + + ",dl_dst=" + found_gateway_mac + + " actions=mod_vlan_vid:" + to_string(destination_vlan_id) + + ",mod_dl_src:" + _host_dvr_mac + + ",mod_dl_dst:" + virtual_mac_address + ",resubmit(,2)"; + } + + ACA_OVS_L2_Programmer::get_instance().execute_openflow(culminative_dataplane_programming_time, + "br-tun", + cmd_string, + "add"); + } + } + if (strcmp(remote_host_ip, "") != 0) { + break; + } + } + if (!is_routing_rule_exist) { new_subnet_routing_table_entry.routing_rules.emplace( current_routing_rule.id(), new_routing_rule_entry);