568 lines
20 KiB
C++
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 */
|