Files
unison/src/openflow/model/openflow-interface.h
2011-05-13 14:58:28 -04:00

568 lines
20 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Blake Hurd <naimorai@gmail.com>
*/
#ifndef OPENFLOW_INTERFACE_H
#define OPENFLOW_INTERFACE_H
#ifdef NS3_OPENFLOW
#include <assert.h>
#include <errno.h>
// Include OFSI code
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/net-device.h"
#include "ns3/packet.h"
#include "ns3/address.h"
#include "ns3/nstime.h"
#include "ns3/mac48-address.h"
#include <set>
#include <map>
#include <limits>
// Include main header and Vendor Extension files
#include "openflow/openflow.h"
#include "openflow/nicira-ext.h"
#include "openflow/ericsson-ext.h"
extern "C"
{
// Inexplicably, the OpenFlow implementation uses these two reserved words as member names.
#define private _private
#define delete _delete
#define list List
// Include OFSI Library files
#include "openflow/private/csum.h"
#include "openflow/private/poll-loop.h"
#include "openflow/private/rconn.h"
#include "openflow/private/stp.h"
#include "openflow/private/vconn.h"
#include "openflow/private/xtoxll.h"
// Include OFSI Switch files
#include "openflow/private/chain.h"
#include "openflow/private/table.h"
#include "openflow/private/datapath.h" // The functions below are defined in datapath.c
uint32_t save_buffer (ofpbuf *);
ofpbuf * retrieve_buffer (uint32_t id);
void discard_buffer (uint32_t id);
#include "openflow/private/dp_act.h" // The functions below are defined in dp_act.c
void set_vlan_vid (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_vlan_pcp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void strip_vlan (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_dl_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_nw_addr (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_tp_port (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_mpls_label (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
void set_mpls_exp (ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
#include "openflow/private/pt_act.h" // The function below is defined in pt_act.c
void update_checksums (ofpbuf *buffer, const sw_flow_key *key, uint32_t old_word, uint32_t new_word);
#undef list
#undef private
#undef delete
}
// Capabilities supported by this implementation.
#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \
| OFPC_TABLE_STATS \
| OFPC_PORT_STATS \
| OFPC_MULTI_PHY_TX \
| OFPC_VPORT_TABLE)
// Actions supported by this implementation.
#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \
| (1 << OFPAT_SET_VLAN_VID) \
| (1 << OFPAT_SET_VLAN_PCP) \
| (1 << OFPAT_STRIP_VLAN) \
| (1 << OFPAT_SET_DL_SRC) \
| (1 << OFPAT_SET_DL_DST) \
| (1 << OFPAT_SET_NW_SRC) \
| (1 << OFPAT_SET_NW_DST) \
| (1 << OFPAT_SET_TP_SRC) \
| (1 << OFPAT_SET_TP_DST) \
| (1 << OFPAT_SET_MPLS_LABEL) \
| (1 << OFPAT_SET_MPLS_EXP) )
#define OFP_SUPPORTED_VPORT_TABLE_ACTIONS ( (1 << OFPPAT_OUTPUT) \
| (1 << OFPPAT_POP_MPLS) \
| (1 << OFPPAT_PUSH_MPLS) \
| (1 << OFPPAT_SET_MPLS_LABEL) \
| (1 << OFPPAT_SET_MPLS_EXP) ) \
namespace ns3 {
class OpenFlowSwitchNetDevice;
namespace ofi {
/**
* \brief Port and its metadata.
*
* We need to store port metadata, because OpenFlow dictates that there
* exists a type of request where the Controller asks for data about a
* port, or multiple ports. Otherwise, we'd refer to it via Ptr<NetDevice>
* everywhere.
*/
struct Port
{
Port () : config (0),
state (0),
netdev (0),
rx_packets (0),
tx_packets (0),
rx_bytes (0),
tx_bytes (0),
tx_dropped (0),
mpls_ttl0_dropped (0)
{
}
uint32_t config; ///< Some subset of OFPPC_* flags.
uint32_t state; ///< Some subset of OFPPS_* flags.
Ptr<NetDevice> netdev;
unsigned long long int rx_packets, tx_packets;
unsigned long long int rx_bytes, tx_bytes;
unsigned long long int tx_dropped;
unsigned long long int mpls_ttl0_dropped;
};
class Stats
{
public:
Stats (ofp_stats_types _type, size_t body_len);
/**
* \brief Prepares to dump some kind of statistics on the connected OpenFlowSwitchNetDevice.
*
* \param body Body member of the struct ofp_stats_request.
* \param body_len Length of the body member.
* \param state State information.
* \return 0 if successful, otherwise a negative error code.
*/
int DoInit (const void *body, int body_len, void **state);
/**
* \brief Appends statistics for OpenFlowSwitchNetDevice to 'buffer'.
*
* \param swtch The OpenFlowSwitchNetDevice this callback is associated with.
* \param state State information.
* \param buffer Buffer to append stats reply to.
* \return 1 if it should be called again later with another buffer, 0 if it is done, or a negative errno value on failure.
*/
int DoDump (Ptr<OpenFlowSwitchNetDevice> swtch, void *state, ofpbuf *buffer);
/**
* \brief Cleans any state created by the init or dump functions.
*
* May not be implemented if no cleanup is required.
*
* \param state State information to clear.
*/
void DoCleanup (void *state);
/**
* \brief State of the FlowStats request/reply.
*/
struct FlowStatsState
{
int table_idx;
sw_table_position position;
ofp_flow_stats_request rq;
time_t now;
ofpbuf *buffer;
};
/**
* \brief State of the PortStats request/reply.
*/
struct PortStatsState
{
uint32_t num_ports; ///< Number of ports in host byte order
uint32_t *ports; ///< Array of ports in network byte order
};
ofp_stats_types type;
private:
int DescStatsDump (void *state, ofpbuf *buffer);
int FlowStatsInit (const void *body, int body_len, void **state);
int (*FlowDumpCallback)(sw_flow *flow, void *state);
int FlowStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, FlowStatsState *s, ofpbuf *buffer);
int AggregateStatsInit (const void *body, int body_len, void **state);
int (*AggregateDumpCallback)(sw_flow *flow, void *state);
int AggregateStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, ofp_aggregate_stats_request *s, ofpbuf *buffer);
int TableStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, void *state, ofpbuf *buffer);
int PortStatsInit (const void *body, int body_len, void **state);
int PortStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, PortStatsState *s, ofpbuf *buffer);
int PortTableStatsDump (Ptr<OpenFlowSwitchNetDevice> dp, void *state, ofpbuf *buffer);
};
/**
* \brief Class for handling flow table actions.
*/
struct Action
{
/**
* \param type Type of Flow Table Action.
* \return true if the provided type is a type of flow table action.
*/
static bool IsValidType (ofp_action_type type);
/**
* \brief Validates the action on whether its data is valid or not.
*
* \param type Type of action to validate.
* \param len Length of the action data.
* \param key Matching key for the flow that is tied to this action.
* \param ah Action's data header.
* \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
*/
static uint16_t Validate (ofp_action_type type, size_t len, const sw_flow_key *key, const ofp_action_header *ah);
/**
* \brief Executes the action.
*
* \param type Type of action to execute.
* \param buffer Buffer of the Packet if it's needed for the action.
* \param key Matching key for the flow that is tied to this action.
* \param ah Action's data header.
*/
static void Execute (ofp_action_type type, ofpbuf *buffer, sw_flow_key *key, const ofp_action_header *ah);
};
/**
* \brief Class for handling virtual port table actions.
*/
struct VPortAction
{
/**
* \param type Type of virtual port table Action.
* \return true if the provided type is a type of virtual port table action.
*/
static bool IsValidType (ofp_vport_action_type type);
/**
* \brief Validates the action on whether its data is valid or not.
*
* \param type Type of action to validate.
* \param len Length of the action data.
* \param ah Action's data header.
* \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
*/
static uint16_t Validate (ofp_vport_action_type type, size_t len, const ofp_action_header *ah);
/**
* \brief Executes the action.
*
* \param type Type of action to execute.
* \param buffer Buffer of the Packet if it's needed for the action.
* \param key Matching key for the flow that is tied to this action.
* \param ah Action's data header.
*/
static void Execute (ofp_vport_action_type type, ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah);
};
/**
* \brief Class for handling Ericsson Vendor-defined actions.
*/
struct EricssonAction
{
/**
* \param type Type of Ericsson Vendor-defined Action.
* \return true if the provided type is a type of Ericsson Vendor-defined action.
*/
static bool IsValidType (er_action_type type);
/**
* \brief Validates the action on whether its data is valid or not.
*
* \param type Type of action to validate.
* \param len Length of the action data.
* \return ACT_VALIDATION_OK if the action checks out, otherwise an error type.
*/
static uint16_t Validate (er_action_type type, size_t len);
/**
* \brief Executes the action.
*
* \param type Type of action to execute.
* \param buffer Buffer of the Packet if it's needed for the action.
* \param key Matching key for the flow that is tied to this action.
* \param ah Action's data header.
*/
static void Execute (er_action_type type, ofpbuf *buffer, const sw_flow_key *key, const er_action_header *ah);
};
/**
* \brief Callback for a stats dump request.
*/
struct StatsDumpCallback
{
bool done; ///< Whether we are done requesting stats.
ofp_stats_request *rq; ///< Current stats request.
Stats *s; ///< Handler of the stats request.
void *state; ///< Stats request state data.
Ptr<OpenFlowSwitchNetDevice> swtch; ///< The switch that we're requesting data from.
};
/**
* \brief Packet Metadata, allows us to track the packet's metadata as it passes through the switch.
*/
struct SwitchPacketMetadata
{
Ptr<Packet> packet; ///< The Packet itself.
ofpbuf* buffer; ///< The OpenFlow buffer as created from the Packet, with its data and headers.
uint16_t protocolNumber; ///< Protocol type of the Packet when the Packet is received
Address src; ///< Source Address of the Packet when the Packet is received
Address dst; ///< Destination Address of the Packet when the Packet is received.
};
/**
* \brief An interface for a Controller of OpenFlowSwitchNetDevices
*
* Follows the OpenFlow specification for a controller.
*/
class Controller : public Object
{
public:
static TypeId GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::ofi::Controller")
.SetParent<Object> ()
.AddConstructor<Controller> ()
;
return tid;
}
virtual ~Controller ()
{
m_switches.clear ();
}
/**
* Adds a switch to the controller.
*
* \param swtch The switch to register.
*/
virtual void AddSwitch (Ptr<OpenFlowSwitchNetDevice> swtch);
/**
* A switch calls this method to pass a message on to the Controller.
*
* \param swtch The switch the message was received from.
* \param buffer The message.
*/
virtual void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer)
{
}
/**
* \brief Starts a callback-based, reliable, possibly multi-message reply to a request made by the controller.
*
* If an incoming request needs to have a reliable reply that might
* require multiple messages, it can use StartDump() to set up
* a callback that will be called as buffer space for replies.
*
* A stats request made by the controller is processed by the switch,
* the switch then calls this method to tell the controller to start
* asking for information. By default (it can be overridden), the
* controller stops all work to run through the callback. ReceiveFromSwitch
* must be defined appropriately to handle the status reply messages
* generated by the switch, or otherwise the status reply messages will be sent
* and discarded.
*
* \param cb The callback data.
*/
void StartDump (StatsDumpCallback* cb);
protected:
/**
* \internal
*
* However the controller is implemented, this method is to
* be used to pass a message on to a switch.
*
* \param swtch The switch to receive the message.
* \param msg The message to send.
* \param length The length of the message.
*/
virtual void SendToSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, void * msg, size_t length);
/**
* \internal
*
* Construct flow data from a matching key to build a flow
* entry for adding, modifying, or deleting a flow.
*
* \param key The matching key data; used to create a flow that matches the packet.
* \param buffer_id The OpenFlow Buffer ID; used to run the actions on the packet if we add or modify the flow.
* \param command Whether to add, modify, or delete this flow.
* \param acts List of actions to execute.
* \param actions_len Length of the actions buffer.
* \param idle_timeout Flow expires if left inactive for this amount of time (specify OFP_FLOW_PERMANENT to disable feature).
* \param hard_timeout Flow expires after this amount of time (specify OFP_FLOW_PERMANENT to disable feature).
* \return Flow data that when passed to SetFlow will add, modify, or delete a flow it defines.
*/
ofp_flow_mod* BuildFlow (sw_flow_key key, uint32_t buffer_id, uint16_t command, void* acts, size_t actions_len, int idle_timeout, int hard_timeout);
/**
* \internal
*
* Get the packet type on the buffer, which can then be used
* to determine how to handle the buffer.
*
* \param buffer The packet in OpenFlow buffer format.
* \return The packet type, as defined in the ofp_type struct.
*/
uint8_t GetPacketType (ofpbuf* buffer);
typedef std::set<Ptr<OpenFlowSwitchNetDevice> > Switches_t;
Switches_t m_switches; ///< The collection of switches registered to this controller.
};
/**
* Demonstration of a Drop controller. When a connected switch
* passes it a packet the switch doesn't recognize, the controller
* configures the switch to make a flow that drops alike packets.
*/
class DropController : public Controller
{
public:
void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer);
};
/**
* Demonstration of a Learning controller. When a connected switch
* passes it a packet the switch doesn't recognize, the controller
* delves into its learned states and figures out if we know what
* port the packet is supposed to go to, flooding if unknown, and
* adjusts the switch's flow table accordingly.
*/
class LearningController : public Controller
{
public:
static TypeId GetTypeId (void);
virtual ~LearningController ()
{
m_learnState.clear ();
}
void ReceiveFromSwitch (Ptr<OpenFlowSwitchNetDevice> swtch, ofpbuf* buffer);
protected:
struct LearnedState
{
uint32_t port; ///< Learned port.
};
Time m_expirationTime; ///< Time it takes for learned MAC state entry/created flow to expire.
typedef std::map<Mac48Address, LearnedState> LearnState_t;
LearnState_t m_learnState; ///< Learned state data.
};
/**
* \brief Executes a list of flow table actions.
*
* \param swtch OpenFlowSwitchNetDevice these actions are being executed on.
* \param packet_uid Packet UID; used to fetch the packet and its metadata.
* \param buffer The Packet OpenFlow buffer.
* \param key The matching key for the flow tied to this list of actions.
* \param actions A buffer of actions.
* \param actions_len Length of actions buffer.
* \param ignore_no_fwd If true, during port forwarding actions, ports that are set to not forward are forced to forward.
*/
void ExecuteActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len, int ignore_no_fwd);
/**
* \brief Validates a list of flow table actions.
*
* \param key The matching key for the flow tied to this list of actions.
* \param actions A buffer of actions.
* \param actions_len Length of actions buffer.
* \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
*/
uint16_t ValidateActions (const sw_flow_key *key, const ofp_action_header *actions, size_t actions_len);
/**
* \brief Executes a list of virtual port table entry actions.
*
* \param swtch OpenFlowSwitchNetDevice these actions are being executed on.
* \param packet_uid Packet UID; used to fetch the packet and its metadata.
* \param buffer The Packet OpenFlow buffer.
* \param key The matching key for the flow tied to this list of actions.
* \param actions A buffer of actions.
* \param actions_len Length of actions buffer.
*/
void ExecuteVPortActions (Ptr<OpenFlowSwitchNetDevice> swtch, uint64_t packet_uid, ofpbuf* buffer, sw_flow_key *key, const ofp_action_header *actions, size_t actions_len);
/**
* \brief Validates a list of virtual port table entry actions.
*
* \param actions A buffer of actions.
* \param actions_len Length of actions buffer.
* \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
*/
uint16_t ValidateVPortActions (const ofp_action_header *actions, size_t actions_len);
/**
* \brief Executes a vendor-defined action.
*
* \param buffer The Packet OpenFlow buffer.
* \param key The matching key for the flow tied to this list of actions.
* \param ah Header of the action.
*/
void ExecuteVendor (ofpbuf *buffer, const sw_flow_key *key, const ofp_action_header *ah);
/**
* \brief Validates a vendor-defined action.
*
* \param key The matching key for the flow tied to this list of actions.
* \param ah Header of the action.
* \param len Length of the action.
* \return If the action list validates, ACT_VALIDATION_OK is returned. Otherwise, a code for the OFPET_BAD_ACTION error type is returned.
*/
uint16_t ValidateVendor (const sw_flow_key *key, const ofp_action_header *ah, uint16_t len);
/*
* From datapath.c
* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID
* into a buffer number (low bits) and a cookie (high bits). The buffer number
* is an index into an array of buffers. The cookie distinguishes between
* different packets that have occupied a single buffer. Thus, the more
* buffers we have, the lower-quality the cookie...
*/
#define PKT_BUFFER_BITS 8
#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS)
#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1)
#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
}
}
#endif // NS3_OPENFLOW
#endif /* OPENFLOW_INTERFACE_H */