/* Copyright (c) 2009-2017 Nicira, Inc.
 *
 * 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 OFPROTO_DPIF_H
#define OFPROTO_DPIF_H 1

/* ofproto-dpif -- DPIF based ofproto implementation.
 *
 * ofproto-dpif provides an ofproto implementation for those platforms which
 * implement the netdev and dpif interface defined in netdev.h and dpif.h.  The
 * most important of which is the Linux Kernel Module (dpif-netlink), but
 * alternatives are supported such as a userspace only implementation
 * (dpif-netdev), and a dummy implementation used for unit testing.
 *
 * ofproto-dpif is divided into three major chunks.
 *
 * - ofproto-dpif.c
 *   The main ofproto-dpif module is responsible for implementing the
 *   provider interface, installing and removing datapath flows, maintaining
 *   packet statistics, running protocols (BFD, LACP, STP, etc), and
 *   configuring relevant submodules.
 *
 * - ofproto-dpif-upcall.c
 *   ofproto-dpif-upcall is responsible for retrieving upcalls from the kernel,
 *   processing miss upcalls, and handing more complex ones up to the main
 *   ofproto-dpif module.  Miss upcall processing boils down to figuring out
 *   what each packet's actions are, executing them (i.e. asking the kernel to
 *   forward it), and handing it up to ofproto-dpif to decided whether or not
 *   to install a kernel flow.
 *
 * - ofproto-dpif-xlate.c
 *   ofproto-dpif-xlate is responsible for translating OpenFlow actions into
 *   datapath actions.
 */

#include <stdint.h>

#include "dpif.h"
#include "fail-open.h"
#include "hmapx.h"
#include "odp-util.h"
#include "id-pool.h"
#include "ovs-atomic.h"
#include "ovs-thread.h"
#include "ofproto-provider.h"
#include "util.h"

struct dpif_flow_stats;
struct ofproto_async_msg;
struct ofproto_dpif;
struct uuid;
struct xlate_cache;
struct xlate_ctx;

/* Number of implemented OpenFlow tables. */
enum { N_TABLES = 255 };
enum { TBL_INTERNAL = N_TABLES - 1 };    /* Used for internal hidden rules. */
BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);

struct rule_dpif {
    struct rule up;

    /* These statistics:
     *
     *   - Do include packets and bytes from datapath flows which have not
     *   recently been processed by a revalidator. */
    struct ovs_mutex stats_mutex;
    struct dpif_flow_detailed_stats stats OVS_GUARDED;

   /* In non-NULL, will point to a new rule (for which a reference is held) to
    * which all the stats updates should be forwarded. This exists only
    * transitionally when flows are replaced.
    *
    * Protected by stats_mutex.  If both 'rule->stats_mutex' and
    * 'rule->new_rule->stats_mutex' must be held together, acquire them in that
    * order, */
    struct rule_dpif *new_rule OVS_GUARDED;
    bool forward_counts OVS_GUARDED;   /* Forward counts? 'used' time will be
                                        * forwarded in all cases. */

    /* If non-zero then the recirculation id that has
     * been allocated for use with this rule.
     * The recirculation id and associated internal flow should
     * be freed when the rule is freed */
    uint32_t recirc_id;
};

struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
                                              ovs_version_t, struct flow *,
                                              struct flow_wildcards *,
                                              const struct dpif_flow_stats *,
                                              uint8_t *table_id,
                                              ofp_port_t in_port,
                                              bool may_packet_in,
                                              bool honor_table_miss,
                                              struct xlate_cache *,
                                              struct hmapx *conj_flows);

void rule_dpif_credit_stats(struct rule_dpif *,
                            const struct dpif_flow_stats *, bool);

void rule_set_recirc_id(struct rule *, uint32_t id);

/* Returns true if 'rule' is an internal rule, false otherwise. */
static inline bool
rule_dpif_is_internal(const struct rule_dpif *rule)
{
    return rule->up.table_id == TBL_INTERNAL;
}

/* Groups. */

enum group_selection_method {
    SEL_METHOD_DEFAULT,
    SEL_METHOD_DP_HASH,
    SEL_METHOD_HASH,
};

struct group_dpif {
    struct ofgroup up;

    /* These statistics:
     *
     *   - Do include packets and bytes from datapath flows which have not
     *   recently been processed by a revalidator. */
    struct ovs_mutex stats_mutex;
    uint64_t packet_count OVS_GUARDED;  /* Number of packets received. */
    uint64_t byte_count OVS_GUARDED;    /* Number of bytes received. */

    enum group_selection_method selection_method;
    enum ovs_hash_alg hash_alg;         /* dp_hash algorithm to be applied. */
    uint32_t hash_basis;                /* Basis for dp_hash. */
    uint32_t hash_mask;                 /* Used to mask dp_hash (2^N - 1).*/
    struct ofputil_bucket **hash_map;   /* Map hash values to buckets. */
};

void group_dpif_credit_stats(struct group_dpif *,
                             struct ofputil_bucket *,
                             const struct dpif_flow_stats *);
struct group_dpif *group_dpif_lookup(struct ofproto_dpif *,
                                     uint32_t group_id, ovs_version_t version,
                                     bool take_ref);


/* Backers.
 *
 * A "backer" is the datapath (dpif) on which an dpif-based bridge (an
 * ofproto-dpif) resides.  A backer can host several bridges, but a bridge is
 * backed by only a single dpif. */


/* DPIF_SUPPORT_FIELD(TYPE, FIELD_NAME, FIELD_DESCRIPTION)
 *
 * Each 'DPIF_SUPPORT_FIELD' defines a member in 'struct dpif_backer_support'
 * and represents support for a datapath action.
 * They are defined as macros to keep 'dpif_show_support()' in sync
 * as new fields are added.  */
#define DPIF_SUPPORT_FIELDS                                                 \
    /* True if the datapath supports masked data in OVS_ACTION_ATTR_SET     \
     * actions. */                                                          \
    DPIF_SUPPORT_FIELD(bool, masked_set_action, "Masked set action")        \
                                                                            \
    /* True if the datapath supports tnl_push and pop actions. */           \
    DPIF_SUPPORT_FIELD(bool, tnl_push_pop, "Tunnel push pop")               \
                                                                            \
    /* True if the datapath supports OVS_FLOW_ATTR_UFID. */                 \
    DPIF_SUPPORT_FIELD(bool, ufid, "Ufid")                                  \
                                                                            \
    /* True if the datapath supports OVS_ACTION_ATTR_TRUNC action. */       \
    DPIF_SUPPORT_FIELD(bool, trunc, "Truncate action")                      \
                                                                            \
    /* True if the datapath supports OVS_ACTION_ATTR_CLONE action. */       \
    DPIF_SUPPORT_FIELD(bool, clone, "Clone action")                         \
                                                                            \
    /* Maximum level of nesting allowed by OVS_ACTION_ATTR_SAMPLE action. */\
    DPIF_SUPPORT_FIELD(size_t, sample_nesting, "Sample nesting")            \
                                                                            \
    /* OVS_CT_ATTR_EVENTMASK supported by OVS_ACTION_ATTR_CT action. */     \
    DPIF_SUPPORT_FIELD(bool, ct_eventmask, "Conntrack eventmask")           \
                                                                            \
    /* True if the datapath supports OVS_ACTION_ATTR_CT_CLEAR action. */    \
    DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear")                   \
                                                                            \
    /* Highest supported dp_hash algorithm. */                              \
    DPIF_SUPPORT_FIELD(size_t, max_hash_alg, "Max dp_hash algorithm")       \
                                                                            \
    /* True if the datapath supports OVS_ACTION_ATTR_CHECK_PKT_LEN. */      \
    DPIF_SUPPORT_FIELD(bool, check_pkt_len, "Check pkt length action")      \
                                                                            \
    /* True if the datapath supports OVS_CT_ATTR_TIMEOUT in                 \
     * OVS_ACTION_ATTR_CT action. */                                        \
    DPIF_SUPPORT_FIELD(bool, ct_timeout, "Conntrack timeout policy")        \
                                                                            \
    /* True if the datapath supports explicit drop action. */               \
    DPIF_SUPPORT_FIELD(atomic_bool, explicit_drop_action,                   \
                       "Explicit Drop action")                              \
                                                                            \
    /* True if the datapath supports balance_tcp optimization */            \
    DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized Balance TCP mode")\
                                                                            \
    /* True if the datapath supports all-zero IP SNAT. */                   \
    DPIF_SUPPORT_FIELD(bool, ct_zero_snat, "Conntrack all-zero IP SNAT")    \
                                                                            \
    /* True if the datapath supports add_mpls action. */                    \
    DPIF_SUPPORT_FIELD(bool, add_mpls, "MPLS Label add")                    \
                                                                            \
    /* True if the datapath supports psample action. */                     \
    DPIF_SUPPORT_FIELD(bool, psample, "psample action")


/* Stores the various features which the corresponding backer supports. */
struct dpif_backer_support {
#define DPIF_SUPPORT_FIELD(TYPE, NAME, TITLE) TYPE NAME;
    DPIF_SUPPORT_FIELDS
#undef DPIF_SUPPORT_FIELD

    /* Each member represents support for related OVS_KEY_ATTR_* fields. */
    struct odp_support odp;
};

/* Reasons that we might need to revalidate every datapath flow, and
 * corresponding coverage counters.
 *
 * A value of 0 means that there is no need to revalidate.
 *
 * It would be nice to have some cleaner way to integrate with coverage
 * counters, but with only a few reasons I guess this is good enough for
 * now. */
enum revalidate_reason {
    REV_RECONFIGURE = 1,       /* Switch configuration changed. */
    REV_STP,                   /* Spanning tree protocol port status change. */
    REV_RSTP,                  /* RSTP port status change. */
    REV_BOND,                  /* Bonding changed. */
    REV_PORT_TOGGLED,          /* Port enabled or disabled by CFM, LACP, ...*/
    REV_FLOW_TABLE,            /* Flow table changed. */
    REV_MAC_LEARNING,          /* Mac learning changed. */
    REV_MCAST_SNOOPING,        /* Multicast snooping changed. */
};

/* All datapaths of a given type share a single dpif backer instance. */
struct dpif_backer {
    char *type;
    int refcount;
    struct dpif *dpif;
    struct udpif *udpif;

    struct ovs_rwlock odp_to_ofport_lock;
    struct hmap odp_to_ofport_map OVS_GUARDED; /* Contains "struct ofport"s. */

    struct simap tnl_backers;      /* Set of dpif ports backing tunnels. */

    enum revalidate_reason need_revalidate; /* Revalidate all flows. */

    bool recv_set_enable; /* Enables or disables receiving packets. */

    /* Meter. */
    struct id_pool *meter_ids;     /* Datapath meter allocation. */

    /* Connection tracking. */
    struct id_pool *tp_ids;             /* Datapath timeout policy id
                                         * allocation. */
    struct cmap ct_zones;               /* "struct ct_zone"s indexed by zone
                                         * id. */
    struct hmap ct_tps;                 /* "struct ct_timeout_policy"s indexed
                                         * by timeout policy (struct simap). */
    struct ovs_list ct_tp_kill_list;    /* A list of timeout policy to be
                                         * deleted. */

    /* Version string of the datapath stored in OVSDB. */
    char *dp_version_string;

    /* Datapath feature support. */
    struct dpif_backer_support bt_support;   /* Boot time support. Set once
                                                when vswitch starts up, then
                                                it is read only through out
                                                the life time of vswitchd. */
    struct dpif_backer_support rt_support;   /* Runtime support. Can be
                                                set to a lower level in
                                                feature than 'bt_support'. */

    struct atomic_count tnl_count;

    struct ovs_list ct_zone_limits_to_add;  /* CT zone limits queued for
                                             * addition into datapath. */
    struct ovs_list ct_zone_limits_to_del;  /* CT zone limits queued for
                                             * deletion from datapath. */
};

/* All existing ofproto_backer instances, indexed by ofproto->up.type. */
extern struct shash all_dpif_backers;

struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t);

/* A bridge based on a "dpif" datapath. */

struct ofproto_dpif {
    /* In 'all_ofproto_dpifs_by_name'. */
    struct hmap_node all_ofproto_dpifs_by_name_node;

    /* In 'all_ofproto_dpifs_by_uuid'. */
    struct hmap_node all_ofproto_dpifs_by_uuid_node;

    struct ofproto up;
    struct dpif_backer *backer;

    /* Unique identifier for this instantiation of this bridge in this running
     * process.  */
    struct uuid uuid;

    ATOMIC(ovs_version_t) tables_version;  /* For classifier lookups. */

    uint64_t dump_seq; /* Last read of udpif_dump_seq(). */

    /* Special OpenFlow rules. */
    struct rule_dpif *miss_rule; /* Sends flow table misses to controller. */
    struct rule_dpif *no_packet_in_rule; /* Drops flow table misses. */
    struct rule_dpif *drop_frags_rule; /* Used in OFPUTIL_FRAG_DROP mode. */

    /* Bridging. */
    struct netflow *netflow;
    struct dpif_sflow *sflow;
    struct dpif_ipfix *ipfix;
    struct dpif_lsample *lsample;
    struct hmap bundles;        /* Contains "struct ofbundle"s. */
    struct mac_learning *ml;
    struct mcast_snooping *ms;
    bool has_bonded_bundles;
    bool lacp_enabled;
    struct mbridge *mbridge;

    struct ovs_mutex stats_mutex;
    struct netdev_stats stats OVS_GUARDED; /* To account packets generated and
                                            * consumed in userspace. */

    /* Spanning tree. */
    struct stp *stp;
    long long int stp_last_tick;

    /* Rapid Spanning Tree. */
    struct rstp *rstp;
    long long int rstp_last_tick;

    /* Ports. */
    struct sset ports;             /* Set of standard port names. */
    struct sset ghost_ports;       /* Ports with no datapath port. */
    struct sset port_poll_set;     /* Queued names for port_poll() reply. */
    int port_poll_errno;           /* Last errno for port_poll() reply. */
    uint64_t change_seq;           /* Connectivity status changes. */

    /* Work queues. */
    struct guarded_list ams;      /* Contains "struct ofproto_async_msgs"s. */
    struct seq *ams_seq;          /* For notifying 'ams' reception. */
    uint64_t ams_seqno;

    bool is_controller_connected; /* True if any controller admitted this
                                   * switch connection. */
    bool explicit_sampled_drops;  /* If explicit drop actions must added after
                                   * trailing sample actions. */
};

struct ofproto_dpif *ofproto_dpif_lookup_by_name(const char *name);
struct ofproto_dpif *ofproto_dpif_lookup_by_uuid(const struct uuid *uuid);

ovs_version_t ofproto_dpif_get_tables_version(struct ofproto_dpif *);

void ofproto_dpif_credit_table_stats(struct ofproto_dpif *, uint8_t table_id,
                                     uint64_t n_matches, uint64_t n_misses);

int ofproto_dpif_execute_actions(struct ofproto_dpif *, ovs_version_t,
                                 const struct flow *, struct rule_dpif *,
                                 const struct ofpact *, size_t ofpacts_len,
                                 struct dp_packet *);
int ofproto_dpif_execute_actions__(struct ofproto_dpif *, ovs_version_t,
                                   const struct flow *, struct rule_dpif *,
                                   const struct ofpact *, size_t ofpacts_len,
                                   int depth, int resubmits,
                                   struct dp_packet *);
void ofproto_dpif_send_async_msg(struct ofproto_dpif *,
                                 struct ofproto_async_msg *);
int ofproto_dpif_send_packet(const struct ofport_dpif *, bool oam,
                             struct dp_packet *);
enum ofperr ofproto_dpif_flow_mod_init_for_learn(
    struct ofproto_dpif *, const struct ofputil_flow_mod *,
    struct ofproto_flow_mod *);

struct ofport_dpif *ofp_port_to_ofport(const struct ofproto_dpif *,
                                       ofp_port_t);

int ofproto_dpif_add_internal_flow(struct ofproto_dpif *,
                                   struct match *, int priority,
                                   uint16_t idle_timeout,
                                   const struct ofpbuf *ofpacts,
                                   struct rule **rulep);
int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
                                      int priority);
int ofproto_dpif_add_lb_output_buckets(struct ofproto_dpif *, uint32_t bond_id,
                                       const ofp_port_t *member_map);
int ofproto_dpif_delete_lb_output_buckets(struct ofproto_dpif *,
                                          uint32_t bond_id);
bool ovs_lb_output_action_supported(struct ofproto_dpif *);

bool ovs_native_tunneling_is_on(struct ofproto_dpif *);

bool ofproto_dpif_ct_zone_timeout_policy_get_name(
    const struct dpif_backer *backer, uint16_t zone, uint16_t dl_type,
    uint8_t nw_proto, char **tp_name, bool *unwildcard);

bool ovs_explicit_drop_action_supported(struct ofproto_dpif *);
bool ovs_psample_supported(struct ofproto_dpif *);

#endif /* ofproto-dpif.h */
