/* Copyright (c) 2008, 2014, 2017 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_14_H
#define OPENFLOW_14_H 1

#include <openflow/openflow-1.3.h>

/* OpenFlow 1.4.1+ specific capabilities
 * (struct ofp_switch_features, member capabilities). */
enum ofp14_capabilities {
    OFPC14_BUNDLES        = 1 << 9,    /* Switch supports bundles. */
    OFPC14_FLOW_MONITORING = 1 << 10,  /* Switch supports flow monitoring. */
};

/* ## ---------- ## */
/* ## ofp14_port ## */
/* ## ---------- ## */

/* Port description property types. */
enum ofp_port_desc_prop_type {
    OFPPDPT14_ETHERNET          = 0,      /* Ethernet property. */
    OFPPDPT14_OPTICAL           = 1,      /* Optical property. */
    OFPPDPT14_EXPERIMENTER      = 0xFFFF, /* Experimenter property. */
};

/* Ethernet port description property. */
struct ofp14_port_desc_prop_ethernet {
    ovs_be16         type;    /* OFPPDPT14_ETHERNET. */
    ovs_be16         length;  /* Length in bytes of this property. */
    uint8_t          pad[4];  /* Align to 64 bits. */
    /* Bitmaps of OFPPF_* that describe features.  All bits zeroed if
     * unsupported or unavailable. */
    ovs_be32 curr;          /* Current features. */
    ovs_be32 advertised;    /* Features being advertised by the port. */
    ovs_be32 supported;     /* Features supported by the port. */
    ovs_be32 peer;          /* Features advertised by peer. */

    ovs_be32 curr_speed;    /* Current port bitrate in kbps. */
    ovs_be32 max_speed;     /* Max port bitrate in kbps */
};
OFP_ASSERT(sizeof(struct ofp14_port_desc_prop_ethernet) == 32);

struct ofp14_port {
    ovs_be32 port_no;
    ovs_be16 length;
    uint8_t pad[2];
    struct eth_addr hw_addr;
    uint8_t pad2[2];                  /* Align to 64 bits. */
    char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */

    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
    ovs_be32 state;         /* Bitmap of OFPPS_* flags. */

    /* Followed by 0 or more OFPPDPT14_* properties. */
};
OFP_ASSERT(sizeof(struct ofp14_port) == 40);


/* ## -------------- ## */
/* ## ofp14_port_mod ## */
/* ## -------------- ## */

enum ofp14_port_mod_prop_type {
    OFPPMPT14_ETHERNET          = 0,      /* Ethernet property. */
    OFPPMPT14_OPTICAL           = 1,      /* Optical property. */
    OFPPMPT14_EXPERIMENTER      = 0xFFFF, /* Experimenter property. */
};

struct ofp14_port_mod {
    ovs_be32 port_no;
    uint8_t pad[4];
    struct eth_addr hw_addr;
    uint8_t pad2[2];
    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
    ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
    /* Followed by 0 or more OFPPMPT14_* properties. */
};
OFP_ASSERT(sizeof(struct ofp14_port_mod) == 24);

/* ## --------------- ## */
/* ## ofp14_table_mod ## */
/* ## --------------- ## */

enum ofp14_table_mod_prop_type {
    OFPTMPT14_EVICTION               = 0x2,    /* Eviction property. */
    OFPTMPT14_VACANCY                = 0x3,    /* Vacancy property. */
    OFPTMPT14_EXPERIMENTER           = 0xFFFF, /* Experimenter property. */
};

enum ofp14_table_mod_prop_eviction_flag {
    OFPTMPEF14_OTHER           = 1 << 0,     /* Using other factors. */
    OFPTMPEF14_IMPORTANCE      = 1 << 1,     /* Using flow entry importance. */
    OFPTMPEF14_LIFETIME        = 1 << 2,     /* Using flow entry lifetime. */
};

/* What changed about the table */
enum ofp14_table_reason {
    OFPTR_VACANCY_DOWN = 3,    /* Vacancy down threshold event. */
    OFPTR_VACANCY_UP   = 4,    /* Vacancy up threshold event. */
#define OFPTR_BITS ((1u << OFPTR_VACANCY_DOWN) | (1u << OFPTR_VACANCY_UP))
};

struct ofp14_table_mod_prop_vacancy {
    ovs_be16         type;   /* OFPTMPT14_VACANCY. */
    ovs_be16         length; /* Length in bytes of this property. */
    uint8_t vacancy_down;    /* Vacancy threshold when space decreases (%). */
    uint8_t vacancy_up;      /* Vacancy threshold when space increases (%). */
    uint8_t vacancy;      /* Current vacancy (%) - only in ofp14_table_desc. */
    uint8_t pad[1];          /* Align to 64 bits. */
};
OFP_ASSERT(sizeof(struct ofp14_table_mod_prop_vacancy) == 8);

struct ofp14_table_mod {
    uint8_t table_id;     /* ID of the table, OFPTT_ALL indicates all tables */
    uint8_t pad[3];         /* Pad to 32 bits */
    ovs_be32 config;        /* Bitmap of OFPTC_* flags */
    /* Followed by 0 or more OFPTMPT14_* properties. */
};
OFP_ASSERT(sizeof(struct ofp14_table_mod) == 8);

/* Body of reply to OFPMP_TABLE_DESC request. */
struct ofp14_table_desc {
    ovs_be16 length;       /* Length is padded to 64 bits. */
    uint8_t table_id;      /* Identifier of table. Lower numbered tables
                              are consulted first. */
    uint8_t pad[1];        /* Align to 32-bits. */
    ovs_be32 config;       /* Bitmap of OFPTC_* values. */
    /* Followed by 0 or more OFPTMPT14_* properties. */
};
OFP_ASSERT(sizeof(struct ofp14_table_desc) == 8);

/* A table config has changed in the datapath */
struct ofp14_table_status {
    uint8_t reason;    /* One of OFPTR_*. */
    uint8_t pad[7];    /* Pad to 64 bits */
    /* Followed by struct ofp14_table_desc */
};
OFP_ASSERT(sizeof(struct ofp14_table_status) == 8);

/* ## ---------------- ## */
/* ## ofp14_port_stats ## */
/* ## ---------------- ## */

enum ofp14_port_stats_prop_type {
    OFPPSPT14_ETHERNET          = 0,      /* Ethernet property. */
    OFPPSPT14_OPTICAL           = 1,      /* Optical property. */
    OFPPSPT14_EXPERIMENTER      = 0xFFFF, /* Experimenter property. */
};

struct ofp14_port_stats_prop_ethernet {
    ovs_be16         type;    /* OFPPSPT14_ETHERNET. */
    ovs_be16         length;  /* Length in bytes of this property. */
    uint8_t          pad[4];  /* Align to 64 bits. */

    ovs_be64 rx_frame_err;   /* Number of frame alignment errors. */
    ovs_be64 rx_over_err;    /* Number of packets with RX overrun. */
    ovs_be64 rx_crc_err;     /* Number of CRC errors. */
    ovs_be64 collisions;     /* Number of collisions. */
};
OFP_ASSERT(sizeof(struct ofp14_port_stats_prop_ethernet) == 40);

struct ofp14_port_stats {
    ovs_be16 length;         /* Length of this entry. */
    uint8_t pad[2];          /* Align to 64 bits. */
    ovs_be32 port_no;
    ovs_be32 duration_sec;   /* Time port has been alive in seconds. */
    ovs_be32 duration_nsec;  /* Time port has been alive in nanoseconds beyond
                                duration_sec. */
    ovs_be64 rx_packets;     /* Number of received packets. */
    ovs_be64 tx_packets;     /* Number of transmitted packets. */
    ovs_be64 rx_bytes;       /* Number of received bytes. */
    ovs_be64 tx_bytes;       /* Number of transmitted bytes. */

    ovs_be64 rx_dropped;     /* Number of packets dropped by RX. */
    ovs_be64 tx_dropped;     /* Number of packets dropped by TX. */
    ovs_be64 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 in properties. */
    ovs_be64 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.) */
    /* Followed by 0 or more OFPPSPT14_* properties. */
};
OFP_ASSERT(sizeof(struct ofp14_port_stats) == 80);


/* ## ----------------- ## */
/* ## ofp14_queue_stats ## */
/* ## ----------------- ## */

struct ofp14_queue_stats {
    ovs_be16 length;         /* Length of this entry. */
    uint8_t pad[6];          /* Align to 64 bits. */
    struct ofp13_queue_stats qs;
    /* Followed by 0 or more properties (none yet defined). */
};
OFP_ASSERT(sizeof(struct ofp14_queue_stats) == 48);


/* ## ---------------- ## */
/* ## ofp14_queue_desc ## */
/* ## ---------------- ## */

struct ofp14_queue_desc_request {
    ovs_be32 port;              /* All ports if OFPP_ANY. */
    ovs_be32 queue;             /* All queues if OFPQ_ALL. */
};
OFP_ASSERT(sizeof(struct ofp14_queue_desc_request) == 8);

/* Body of reply to OFPMP_QUEUE_DESC request. */
struct ofp14_queue_desc {
    ovs_be32 port_no;           /* Port this queue is attached to. */
    ovs_be32 queue_id;          /* ID for the specific queue. */
    ovs_be16 len;               /* Length in bytes of this queue desc. */
    uint8_t pad[6];             /* 64-bit alignment. */
};
OFP_ASSERT(sizeof(struct ofp14_queue_desc) == 16);

enum ofp14_queue_desc_prop_type {
    OFPQDPT14_MIN_RATE = 1,
    OFPQDPT14_MAX_RATE = 2,
    OFPQDPT14_EXPERIMENTER = 0xffff
};

/* ## -------------- ## */
/* ## Miscellaneous. ## */
/* ## -------------- ## */

/* Request forward reason */
enum ofp14_requestforward_reason {
    OFPRFR_GROUP_MOD = 0,      /* Forward group mod requests. */
    OFPRFR_METER_MOD = 1,      /* Forward meter mod requests. */
    OFPRFR_N_REASONS           /* Denotes number of reasons. */
};

/* Role status event message. */
struct ofp14_role_status {
    ovs_be32 role;              /* One of OFPCR_ROLE_*. */
    uint8_t  reason;            /* One of OFPCRR_*. */
    uint8_t  pad[3];            /* Align to 64 bits. */
    ovs_be64 generation_id;     /* Primary Election Generation Id */

    /* Followed by a list of struct ofp14_role_prop_header */
};
OFP_ASSERT(sizeof(struct ofp14_role_status) == 16);

/* What changed about the controller role */
enum ofp14_controller_role_reason {
    OFPCRR_PRIMARY_REQUEST = 0, /* Another controller asked to be primary. */
    OFPCRR_CONFIG          = 1, /* Configuration changed on the switch. */
    OFPCRR_EXPERIMENTER    = 2, /* Experimenter data changed. */
    OFPCRR_N_REASONS            /* Denotes number of reasons. */
};

/* Role property types.
*/
enum ofp14_role_prop_type {
    OFPRPT_EXPERIMENTER         = 0xFFFF, /* Experimenter property. */
};

/* Group/Meter request forwarding. */
struct ofp14_requestforward {
    struct ofp_header request;  /* Request being forwarded. */
};
OFP_ASSERT(sizeof(struct ofp14_requestforward) == 8);

/* Bundle control message types */
enum ofp14_bundle_ctrl_type {
    OFPBCT_OPEN_REQUEST    = 0,
    OFPBCT_OPEN_REPLY      = 1,
    OFPBCT_CLOSE_REQUEST   = 2,
    OFPBCT_CLOSE_REPLY     = 3,
    OFPBCT_COMMIT_REQUEST  = 4,
    OFPBCT_COMMIT_REPLY    = 5,
    OFPBCT_DISCARD_REQUEST = 6,
    OFPBCT_DISCARD_REPLY   = 7,
};

/* Bundle configuration flags. */
enum ofp14_bundle_flags {
    OFPBF_ATOMIC  = 1 << 0,  /* Execute atomically. */
    OFPBF_ORDERED = 1 << 1,  /* Execute in specified order. */
};

/* Message structure for OFPT_BUNDLE_CONTROL and OFPT_BUNDLE_ADD_MESSAGE. */
struct ofp14_bundle_ctrl_msg {
    ovs_be32 bundle_id;     /* Identify the bundle. */
    ovs_be16 type;          /* OFPT_BUNDLE_CONTROL: one of OFPBCT_*.
                             * OFPT_BUNDLE_ADD_MESSAGE: not used. */
    ovs_be16 flags;         /* Bitmap of OFPBF_* flags. */
    /* Followed by:
     * - For OFPT_BUNDLE_ADD_MESSAGE only, an encapsulated OpenFlow message,
     *   beginning with an ofp_header whose xid is identical to this message's
     *   outer xid.
     * - For OFPT_BUNDLE_ADD_MESSAGE only, and only if at least one property is
     *   present, 0 to 7 bytes of padding to align on a 64-bit boundary.
     * - Zero or more properties (see struct ofp14_bundle_prop_header). */
};
OFP_ASSERT(sizeof(struct ofp14_bundle_ctrl_msg) == 8);

/* Body for ofp14_multipart_request of type OFPMP_FLOW_MONITOR.
 *
 * The OFPMP_FLOW_MONITOR request's body consists of an array of zero or more
 * instances of this structure. The request arranges to monitor the flows
 * that match the specified criteria, which are interpreted in the same way as
 * for OFPMP_FLOW.
 *
 * 'id' identifies a particular monitor for the purpose of allowing it to be
 * canceled later with OFPFMC_DELETE. 'id' must be unique among
 * existing monitors that have not already been canceled.
 */
struct ofp14_flow_monitor_request {
    ovs_be32 monitor_id;        /* Controller-assigned ID for this monitor. */
    ovs_be32 out_port;          /* Required output port, if not OFPP_ANY. */
    ovs_be32 out_group;         /* Required output port, if not OFPG_ANY. */
    ovs_be16 flags;             /* OFPMF14_*. */
    uint8_t table_id;           /* One table's ID or OFPTT_ALL (all tables). */
    uint8_t command;            /* One of OFPFMC14_*. */
    /* Followed by an ofp11_match structure. */
};
OFP_ASSERT(sizeof(struct ofp14_flow_monitor_request) == 16);

/* Flow monitor commands */
enum ofp14_flow_monitor_command {
    OFPFMC_ADD = 0, /* New flow monitor. */
    OFPFMC_MODIFY = 1, /* Modify existing flow monitor. */
    OFPFMC_DELETE = 2, /* Delete/cancel existing flow monitor. */
};

/* 'flags' bits in struct of_flow_monitor_request. */
enum ofp14_flow_monitor_flags {
    /* When to send updates. */
    /* Common to NX and OpenFlow 1.4 */
    OFPFMF_INITIAL = 1 << 0,     /* Initially matching flows. */
    OFPFMF_ADD = 1 << 1,         /* New matching flows as they are added. */
    OFPFMF_REMOVED = 1 << 2,     /* Old matching flows as they are removed. */
    OFPFMF_MODIFY = 1 << 3,      /* Matching flows as they are changed. */

    /* What to include in updates. */
    /* Common to NX and OpenFlow 1.4 */
    OFPFMF_INSTRUCTIONS = 1 << 4, /* If set, instructions are included. */
    OFPFMF_NO_ABBREV = 1 << 5,    /* If set, include own changes in full. */
    /* OpenFlow 1.4 */
    OFPFMF_ONLY_OWN = 1 << 6,     /* If set, don't include other controllers.
                                     */
};

/* OFPMP_FLOW_MONITOR reply header.
 *
 * The body of an OFPMP_FLOW_MONITOR reply is an array of variable-length
 * structures, each of which begins with this header.  The 'length' member may
 * be used to traverse the array, and the 'event' member may be used to
 * determine the particular structure.
 * Every instance is a multiple of 8 bytes long. */
struct ofp_flow_update_header {
    ovs_be16 length;                /* Length of this entry. */
    ovs_be16 event;                 /* One of OFPFME_*. */
    /* ...other data depending on 'event'... */
};
OFP_ASSERT(sizeof(struct ofp_flow_update_header) == 4);

/* 'event' values in struct ofp_flow_update_header. */
enum ofp_flow_update_event {
    /* struct ofp_flow_update_full. */
    OFPFME_INITIAL = 0,          /* Flow present when flow monitor created. */
    OFPFME_ADDED = 1,            /* Flow was added. */
    OFPFME_REMOVED = 2,          /* Flow was removed. */
    OFPFME_MODIFIED = 3,         /* Flow instructions were changed. */

    /* struct ofp_flow_update_abbrev. */
    OFPFME_ABBREV = 4,           /* Abbreviated reply. */

    /* struct ofp_flow_update_header. */
    OFPFME_PAUSED = 5,           /* Monitoring paused (out of buffer space). */
    OFPFME_RESUMED = 6,          /* Monitoring resumed. */
};

/* OFPMP_FLOW_MONITOR reply for OFPFME_INITIAL, OFPFME_ADDED, OFPFME_REMOVED,
 * and OFPFME_MODIFIED. */
struct ofp_flow_update_full {
    ovs_be16 length;           /* Length is 32 + match + instructions. */
    ovs_be16 event;            /* One of OFPFME_*. */
    uint8_t table_id;          /* ID of flow's table. */
    uint8_t reason;            /* OFPRR_* for OFPFME_REMOVED, else zero. */
    ovs_be16 idle_timeout;     /* Number of seconds idle before expiration. */
    ovs_be16 hard_timeout;     /* Number of seconds before expiration. */
    ovs_be16 priority;         /* Priority of the entry. */
    uint8_t zeros[4];          /* Reserved, currently zeroed. */
    ovs_be64 cookie;           /* Opaque controller-issued identifier. */
    /* Instruction set.
     *      If OFPFMF_INSTRUCTIONS was not specified, or 'event' is
     *     OFPFME_REMOVED, no instructions are included.
     */
};
OFP_ASSERT(sizeof(struct ofp_flow_update_full) == 24);

/* OFPMP_FLOW_MONITOR reply for OFPFME_ABBREV.
 *
 * When the controller does not specify OFPFMF_NO_ABBREV in a monitor request,
 * any flow tables changes due to the controller's own requests (on the same
 * OpenFlow channel) will be abbreviated, when possible, to this form, which
 * simply specifies the 'xid' of the OpenFlow request (e.g. an OFPT_FLOW_MOD)
 * that caused the change.
 * Some changes cannot be abbreviated and will be sent in full.
 */
struct ofp_flow_update_abbrev {
    ovs_be16 length;     /* Length is 8. */
    ovs_be16 event;      /* OFPFME_ABBREV. */
    ovs_be32 xid;        /* Controller-specified xid from flow_mod. */
};
OFP_ASSERT(sizeof(struct ofp_flow_update_abbrev) == 8);

/* OFPMP_FLOW_MONITOR reply for OFPFME_PAUSED and OFPFME_RESUMED.*/
struct ofp_flow_update_paused {
    ovs_be16 length;      /* Length is 8. */
    ovs_be16 event;       /* One of OFPFME_*. */
    uint8_t zeros[4];     /* Reserved, currently zeroed. */
};
OFP_ASSERT(sizeof(struct ofp_flow_update_paused) == 8);

#endif /* openflow/openflow-1.4.h */
