/*
 *
 * Definitions for packet ring
 *
 * 2004-26 - ntop
 *
 */

#ifndef __RING_H
#define __RING_H

/**
 * @file pf_ring.h
 *
 * @brief      PF_RING kernel module header file.
 * @details    This header file should NOT be included in PF_RING-based applications directly.
 */

#ifdef __KERNEL__
#include <linux/in6.h>

#else /* Userspace*/

#include <netinet/in.h>

#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define __LITTLE_ENDIAN_BITFIELD
#elif __BYTE_ORDER == __BIG_ENDIAN
#define __BIG_ENDIAN_BITFIELD
#else
# error "Unknown byte order"
#endif

#endif /* __KERNEL__ */

/* Versioning */
#define RING_VERSION                "9.3.0"
#define RING_VERSION_NUM           0x090300

/* Increment whenever there is a change in some shared data structure
 * between kernel and userspace, including ioctl or packet header layout */
#define RING_FLOWSLOT_VERSION          21

#define RING_MAGIC
#define RING_MAGIC_VALUE             0x88

#define RING_USE_SOCKADDR_LL /* use sockaddr_ll instead of sockaddr */

#define MIN_NUM_SLOTS                 512
#define DEFAULT_NUM_SLOTS            4096
#define DEFAULT_BUCKET_LEN            128
#define MAX_NUM_DEVICES               256

#define MAX_NUM_RING_SOCKETS          512

#define MAX_CLUSTER_QUEUES             64

/* Watermark */
#define DEFAULT_MIN_PKT_QUEUED        128
#define DEFAULT_POLL_WATERMARK_TIMEOUT  0

#define FILTERING_SAMPLING_RATIO       10

/* Set */
#define SO_ADD_TO_CLUSTER                 99
#define SO_REMOVE_FROM_CLUSTER           100
#define SO_SET_STRING                    101
#define SO_ADD_FILTERING_RULE            102
#define SO_REMOVE_FILTERING_RULE         103
#define SO_TOGGLE_FILTER_POLICY          104
#define SO_SET_SAMPLING_RATE             105
#define SO_ACTIVATE_RING                 106
#define SO_RING_BUCKET_LEN               107
#define SO_SET_CHANNEL_ID                108
#define SO_PURGE_IDLE_HASH_RULES         109 /* inactivity (sec) */
#define SO_SET_APPL_NAME                 110
#define SO_SET_PACKET_DIRECTION          111
#define SO_SET_MASTER_RING               112
#define SO_ADD_HW_FILTERING_RULE         113
#define SO_DEL_HW_FILTERING_RULE         114
#define SO_DISCARD_INJECTED_PKTS         115 /* discard stack injected packets */
#define SO_DEACTIVATE_RING               116
#define SO_SET_POLL_WATERMARK            117
#define SO_SET_VIRTUAL_FILTERING_DEVICE  118
#define SO_REHASH_RSS_PACKET             119
#define SO_SET_FILTERING_SAMPLING_RATE   120
#define SO_SET_POLL_WATERMARK_TIMEOUT    121
#define SO_SET_DEV_TIME                  122
#define SO_ADJ_DEV_TIME                  123
#define SO_SHUTDOWN_RING                 124
#define SO_PURGE_IDLE_RULES              125 /* inactivity (sec) */
#define SO_SET_SOCKET_MODE               126
#define SO_USE_SHORT_PKT_HEADER          127
#define SO_CONTROL_DEV_QUEUE             128
#define SO_ENABLE_RX_PACKET_BOUNCE       131
#define SO_SET_APPL_STATS                133
#define SO_SET_STACK_INJECTION_MODE      134 /* stack injection/interception from userspace */
#define SO_CREATE_CLUSTER_REFEREE        135
#define SO_PUBLISH_CLUSTER_OBJECT        136
#define SO_LOCK_CLUSTER_OBJECT           137
#define SO_UNLOCK_CLUSTER_OBJECT         138
#define SO_SET_CUSTOM_BOUND_DEV_NAME     139
#define SO_SET_IFF_PROMISC               140
#define SO_SET_VLAN_ID                   141

/* Get */
#define SO_GET_RING_VERSION              170
#define SO_GET_FILTERING_RULE_STATS      171
#define SO_GET_HASH_FILTERING_RULE_STATS 172
#define SO_GET_ZC_DEVICE_INFO            173
#define SO_GET_NUM_RX_CHANNELS           174
#define SO_GET_RING_ID                   175
#define SO_GET_BPF_EXTENSIONS            176
#define SO_GET_BOUND_DEVICE_ADDRESS      177
#define SO_GET_NUM_QUEUED_PKTS           178
#define SO_GET_PKT_HEADER_LEN            179
#define SO_GET_LOOPBACK_TEST             180
#define SO_GET_BUCKET_LEN                181
#define SO_GET_DEVICE_TYPE               182
#define SO_GET_EXTRA_DMA_MEMORY          183
#define SO_GET_BOUND_DEVICE_IFINDEX      184
#define SO_GET_DEVICE_IFINDEX            185
#define SO_GET_APPL_STATS_FILE_NAME      186
#define SO_GET_LINK_STATUS               187
#define SO_GET_DEV_TX_TIME               188
#define SO_GET_DEV_STATS                 189
#define SO_SELECT_ZC_DEVICE              190
#define SO_GET_CLUSTER_OBJECT_INFO       191

/* Error codes */
#define PF_RING_ERROR_GENERIC              -1
#define PF_RING_ERROR_INVALID_ARGUMENT     -2
#define PF_RING_ERROR_NO_PKT_AVAILABLE     -3
#define PF_RING_ERROR_NO_TX_SLOT_AVAILABLE -4
#define PF_RING_ERROR_WRONG_CONFIGURATION  -5
#define PF_RING_ERROR_END_OF_DEMO_MODE     -6
#define PF_RING_ERROR_NOT_SUPPORTED        -7
#define PF_RING_ERROR_INVALID_LIB_VERSION  -8
#define PF_RING_ERROR_UNKNOWN_ADAPTER      -9
#define PF_RING_ERROR_NOT_ENOUGH_MEMORY   -10
#define PF_RING_ERROR_INVALID_STATUS      -11
#define PF_RING_ERROR_RING_NOT_ENABLED    -12
#define PF_RING_ERROR_BAD_IFNAME          -13
#define PF_RING_ERROR_MOD_NOT_LOADED      -14
#define PF_RING_ERROR_UNABLE_TO_MAP       -15
#define PF_RING_ERROR_UNABLE_TO_GET_INFO  -16
#define PF_RING_ERROR_MMAP_FAILURE        -17
#define PF_RING_ERROR_INIT_FAILURE        -18

#define REFLECTOR_NAME_LEN                 8

#ifndef IN6ADDR_ANY_INIT
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
#endif

/* *********************************** */

#ifdef __KERNEL__

#if(LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0))

/* From linux 5.4.34 */
typedef long __kernel_time_t;

struct timeval {
  __kernel_time_t      tv_sec;  /* seconds */
  __kernel_suseconds_t tv_usec; /* microseconds */
};

struct timespec {
  __kernel_time_t      tv_sec;  /* seconds */
  long                 tv_nsec; /* nanoseconds */
};

struct timespec ns_to_timespec(const s64 nsec);
struct timeval ns_to_timeval(const s64 nsec);

#define ktime_to_timeval(kt) ns_to_timeval((kt))

#endif

#endif

/*
  Note that as offsets *can* be negative,
  please do not change them to unsigned
*/
struct pkt_offset {
  /* This 'eth_offset' offset *must* be added to all offsets below
   * ONLY if you are inside the kernel. Ignore it in user-space. */
  int16_t eth_offset;

  int16_t vlan_offset;
  int16_t l3_offset;
  int16_t l4_offset;
  int16_t payload_offset;
} __attribute__((packed));

#ifndef ETH_ALEN
#define ETH_ALEN  6
#endif

#define REFLECT_PACKET_DEVICE_NONE     0

typedef union {
  struct in6_addr v6;  /* IPv6 src/dst IP addresses (Network byte order) */
  u_int32_t v4;        /* IPv4 src/dst IP addresses */
} ip_addr;

#define ipv4_tos     ip_tos
#define ipv6_tos     ip_tos
#define ipv4_src     ip_src.v4
#define ipv4_dst     ip_dst.v4
#define ipv6_src     ip_src.v6
#define ipv6_dst     ip_dst.v6
#define host4_low    host_low.v4
#define host4_high   host_high.v4
#define host6_low    host_low.v6
#define host6_high   host_high.v6
#define host4_peer_a host_peer_a.v4
#define host4_peer_b host_peer_b.v4
#define host6_peer_a host_peer_a.v6
#define host6_peer_b host_peer_b.v6

struct eth_vlan_hdr {
  u_int16_t h_vlan_id; /* Tag Control Information (QoS, VLAN ID) */
  u_int16_t h_proto;   /* packet type ID field */
} __attribute__((packed));

#define NEXTHDR_HOP               0
#define NEXTHDR_IPV6             41
#define NEXTHDR_ROUTING          43
#define NEXTHDR_FRAGMENT         44
#define NEXTHDR_ESP              50
#define NEXTHDR_AUTH             51
#define NEXTHDR_NONE             59
#define NEXTHDR_DEST             60
#define NEXTHDR_MOBILITY        135

struct kcompact_ipv6_hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
  u_int8_t priority:4,
           version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
  u_int8_t version:4,
           priority:4;
#endif
  u_int8_t              flow_lbl[3];
  u_int16_t         payload_len;
  u_int8_t          nexthdr;
  u_int8_t          hop_limit;
  struct in6_addr saddr;
  struct in6_addr daddr;
} __attribute__((packed));

struct kcompact_ipv6_opt_hdr {
  u_int8_t          nexthdr;
  u_int8_t          hdrlen;
  u_int8_t          padding[6];
} __attribute__((packed));

#define GRE_HEADER_CHECKSUM     0x8000
#define GRE_HEADER_ROUTING      0x4000
#define GRE_HEADER_KEY          0x2000
#define GRE_HEADER_SEQ_NUM      0x1000
#define GRE_HEADER_VERSION      0x0007

struct gre_header {
  u_int16_t flags_and_version;
  u_int16_t proto;
  /* Optional fields */
} __attribute__((packed));

#define GTP_SIGNALING_PORT      2123
#define GTP_U_DATA_PORT         2152

#define GTP_VERSION_1           0x1
#define GTP_VERSION_2           0x2
#define GTP_PROTOCOL_TYPE       0x1

struct gtp_v1_hdr {
#define GTP_FLAGS_VERSION       0xE0
#define GTP_FLAGS_VERSION_SHIFT 5
#define GTP_FLAGS_PROTOCOL_TYPE 0x10
#define GTP_FLAGS_RESERVED      0x08
#define GTP_FLAGS_EXTENSION     0x04
#define GTP_FLAGS_SEQ_NUM       0x02
#define GTP_FLAGS_NPDU_NUM      0x01
  u_int8_t  flags;
  u_int8_t  message_type;
  u_int16_t payload_len;
  u_int32_t teid;
} __attribute__((__packed__));

/* Optional: GTP_FLAGS_EXTENSION | GTP_FLAGS_SEQ_NUM | GTP_FLAGS_NPDU_NUM */
struct gtp_v1_opt_hdr {
  u_int16_t seq_num;
  u_int8_t  npdu_num;
  u_int8_t  next_ext_hdr;
} __attribute__((__packed__));

/* Optional: GTP_FLAGS_EXTENSION && next_ext_hdr != 0 */
struct gtp_v1_ext_hdr {
#define GTP_EXT_HDR_LEN_UNIT_BYTES 4
  u_int8_t len; /* 4-byte unit */
  /*
   * u_char   contents[len*4-2];
   * u_int8_t next_ext_hdr;
   */
} __attribute__((__packed__));

#define NO_TUNNEL_ID     0xFFFFFFFF

/* Tunneling Protocols (e.g. GTP) */
typedef struct {
  u_int32_t tunnel_id; /* GTP/GRE tunnelId or NO_TUNNEL_ID for no filtering */
  u_int8_t  tunneled_dmac[ETH_ALEN], tunneled_smac[ETH_ALEN];  /* MAC src/dst addresses */
  u_int16_t tunneled_eth_type;         /* Ethernet type */
  u_int8_t tunneled_ip_version; /* Layer 4 protocol */
  u_int8_t tunneled_proto; /* Layer 4 protocol */
  ip_addr tunneled_ip_src, tunneled_ip_dst;
  u_int16_t tunneled_l4_src_port, tunneled_l4_dst_port;
} __attribute__((packed))
tunnel_info;

#define MOBILE_IP_PORT           434

struct mobile_ip_hdr {
  u_int8_t message_type, next_header;
  u_int16_t reserved;
} __attribute__((packed));

#define VXLAN_IP_PORT           4789

struct vxlan_hdr {
  u_int8_t flags[2];
  u_int16_t gdp;
  u_int8_t vni[3];
  u_int8_t res;
} __attribute__((packed));

typedef enum {
  long_pkt_header = 0, /* it includes PF_RING-extensions over the original pcap header */
  short_pkt_header     /* Short pcap-like header */
} pkt_header_len;

struct pkt_parsing_info {
  /* Core fields (also used by NetFlow) */
  u_int8_t  dmac[ETH_ALEN], smac[ETH_ALEN];  /* MAC src/dst addresses */
  u_int16_t eth_type;         /* Ethernet type */
  u_int16_t vlan_id;          /* VLAN Id or NO_VLAN */
  u_int16_t qinq_vlan_id;     /* VLAN Id or NO_VLAN */
  u_int8_t  ip_version;
  u_int8_t  l3_proto, ip_tos; /* Layer 3 protocol, TOS */
  ip_addr   ip_src, ip_dst;   /* IPv4/6 src/dst IP addresses */
  u_int16_t l4_src_port, l4_dst_port;/* Layer 4 src/dst ports */
  u_int8_t  icmp_type, icmp_code;    /* Variables for ICMP packets */
  struct {
    u_int8_t flags;   /* TCP flags (0 if not available) */
    u_int32_t seq_num, ack_num; /* TCP sequence number */
  } tcp;
  tunnel_info tunnel;
  int32_t last_matched_rule_id; /* If > 0 identifies a rule that matched the packet */
  struct pkt_offset offset; /* Offsets of L3/L4/payload elements */
} __attribute__((packed));

#define UNKNOWN_INTERFACE          -1
#define FAKE_PACKET                -2 /* It indicates that the returned packet
                                         is faked, and that the info is basically
                                         a message from PF_RING
                                      */

struct pfring_extended_pkthdr {
  u_int64_t timestamp_ns;  /* Packet timestamp at ns precision. Note that if your NIC supports
                              hardware timestamp, this is the place to read timestamp from */
#define PKT_FLAGS_CHECKSUM_OFFLOAD    1 << 0 /* IP/TCP checksum offload enabled */
#define PKT_FLAGS_CHECKSUM_OK         1 << 1 /* Valid checksum (with IP/TCP checksum offload enabled) */
#define PKT_FLAGS_IP_MORE_FRAG        1 << 2 /* IP More fragments flag set */
#define PKT_FLAGS_IP_FRAG_OFFSET      1 << 3 /* IP fragment offset set (not 0) */
#define PKT_FLAGS_VLAN_HWACCEL        1 << 4 /* VLAN stripped by hw */
#define PKT_FLAGS_FLOW_HIT            1 << 5 /* PF_RING_FLOW_OFFLOAD: flow hit */
#define PKT_FLAGS_FLOW_MISS           1 << 6 /* PF_RING_FLOW_OFFLOAD: flow miss */
#define PKT_FLAGS_FLOW_UNHANDLED      1 << 7 /* PF_RING_FLOW_OFFLOAD: flow unhandled */
  u_int32_t flags;

  u_int8_t rx_direction;   /* 1=RX: packet received by the NIC, 0=TX: packet transmitted by the NIC */
  u_int8_t port_id;        /* Port ID (when exported by devices like Arista MetaWatch) */
  u_int16_t device_id;     /* Device ID (when exported by devices like Arista MetaWatch) */

  int32_t  if_index;       /* index of the interface on which the packet has been received.
                              It can be also used to report other information */

  u_int32_t pkt_hash;      /* Hash based on the packet header */

  /* --- short header ends here --- */

  struct {
    int32_t bounce_interface; /* Interface Id where this packet will bounce after processing
                                 if its values is other than UNKNOWN_INTERFACE */
    struct sk_buff *reserved; /* Kernel only pointer */
  } tx;

  struct {
    u_int32_t pid /* process id */;
  } process;

  /* NOTE: leave it as last field of the memset on parse_pkt() will fail */
  struct pkt_parsing_info parsed_pkt; /* packet parsing info */
} __attribute__((packed));

/* NOTE: Keep 'struct pfring_pkthdr' in sync with 'struct pcap_pkthdr' */

struct pfring_pkthdr {
  /* pcap header */
  struct timeval ts;    /* time stamp */
  u_int32_t caplen;     /* length of portion present */
  u_int32_t len;        /* length of whole packet (off wire) */
  struct pfring_extended_pkthdr extended_hdr; /* PF_RING extended header */
} __attribute__((packed));

/* *********************************** */

#define MAX_NUM_LIST_ELEMENTS MAX_NUM_RING_SOCKETS /* sizeof(bits_set) [see below] */

#ifdef __KERNEL__
typedef struct {
  u_int32_t num_elements, top_element_id;
  spinlock_t list_lock;
  void *list_elements[MAX_NUM_LIST_ELEMENTS];
} lockless_list;

void init_lockless_list(lockless_list *l);
int lockless_list_add(lockless_list *l, void *elem);
int lockless_list_remove(lockless_list *l, void *elem);
void* lockless_list_get_next(lockless_list *l, u_int32_t *last_list_idx);
void* lockless_list_get_first(lockless_list *l, u_int32_t *last_list_idx);
void lockless_list_empty(lockless_list *l, u_int8_t free_memory);
void term_lockless_list(lockless_list *l, u_int8_t free_memory);
#endif

/* ************************************************* */

typedef struct {
  int32_t if_index;                    /* Index of the interface on which the packet has been received */
  u_int8_t smac[ETH_ALEN], dmac[ETH_ALEN]; /* Use '0' (zero-ed MAC address) for any MAC address.
                                              This is applied to both source and destination. */
  u_int16_t vlan_id;                   /* Use 0 for any vlan */
  u_int16_t eth_type;                       /* Use 0 for any ethernet type */
  u_int8_t  proto;                     /* Use 0 for any l3 protocol */
  ip_addr   shost, dhost;              /* User '0' for any host. This is applied to both source and destination. */
  ip_addr   shost_mask, dhost_mask;    /* IPv4/6 network mask */
  u_int16_t sport_low, sport_high;     /* All ports between port_low...port_high means 'any' port */
  u_int16_t dport_low, dport_high;     /* All ports between port_low...port_high means 'any' port */
  struct {
    u_int8_t flags;             /* TCP flags (0 if not available) */
  } tcp;
} __attribute__((packed))
filtering_rule_core_fields;

/* ************************************************* */

typedef struct {

#define FILTER_TUNNEL_ID_FLAG 1 << 0
  u_int16_t optional_fields;          /* Use this mask to activate optional fields */

  struct {
    u_int32_t tunnel_id;              /* GTP/GRE tunnelId or NO_TUNNEL_ID for no filtering */
    ip_addr   shost, dhost;           /* Filter on tunneled IPs */
    ip_addr   shost_mask, dhost_mask; /* IPv4/6 network mask */
  } tunnel;

  char payload_pattern[32];         /* If strlen(payload_pattern) > 0, the packet payload
                                       must match the specified pattern */
} __attribute__((packed))
filtering_rule_extended_fields;

/* ************************************************* */

#define FILTERING_RULE_AUTO_RULE_ID 0xFFFF

typedef enum {
  forward_packet_and_stop_rule_evaluation = 0,
  dont_forward_packet_and_stop_rule_evaluation,
  execute_action_and_continue_rule_evaluation,
  execute_action_and_stop_rule_evaluation,
  forward_packet_add_rule_and_stop_rule_evaluation, /* auto-filled hash rule */
  reflect_packet_and_stop_rule_evaluation,
  reflect_packet_and_continue_rule_evaluation,
  bounce_packet_and_stop_rule_evaluation,
  bounce_packet_and_continue_rule_evaluation
} rule_action_behaviour;

typedef enum {
  pkt_detail_flow,
  pkt_detail_aggregation
} pkt_detail_mode;

typedef enum {
  rx_and_tx_direction = 0,
  rx_only_direction,
  tx_only_direction
} packet_direction;

typedef enum {
  send_and_recv_mode = 0,
  send_only_mode,
  recv_only_mode,
  management_only_mode
} socket_mode;

typedef struct {
  unsigned long jiffies_last_match;  /* Jiffies of the last rule match (updated by pf_ring) */
  struct net_device *reflector_dev;  /* Reflector device */
} __attribute__((packed))
filtering_internals;

typedef struct {
  /* FILTERING_RULE_AUTO_RULE_ID to auto generate a rule ID */
  u_int16_t rule_id;                 /* Rules are processed in order from lowest to highest id */

  rule_action_behaviour rule_action; /* What to do in case of match */
  u_int8_t balance_id, balance_pool; /* If balance_pool > 0, then pass the packet above only if the
                                        (hash(proto, sip, sport, dip, dport) % balance_pool) = balance_id */
  u_int8_t locked;                     /* Do not purge with pfring_purge_idle_rules() */
  u_int8_t bidirectional;             /* Swap peers when checking if they match the rule. Default: monodir */
  filtering_rule_core_fields     core_fields;
  filtering_rule_extended_fields extended_fields;
  char reflector_device_name[REFLECTOR_NAME_LEN];

  filtering_internals internals;   /* PF_RING internal fields */
} __attribute__((packed))
filtering_rule;

/* *********************************** */

/* 82599 packet steering filters */

typedef struct {
  u_int8_t  proto;
  u_int32_t s_addr, d_addr;
  u_int16_t s_port, d_port;
  u_int16_t queue_id;
} __attribute__((packed))
intel_82599_five_tuple_filter_hw_rule;

typedef struct {
  u_int16_t vlan_id;
  u_int8_t  proto;
  u_int32_t s_addr, d_addr;
  u_int16_t s_port, d_port;
  u_int16_t queue_id;
} __attribute__((packed))
intel_82599_perfect_filter_hw_rule;

/*
  Rules are defined per port. Each redirector device
  has 4 ports (numbered 0..3):

         0   +--------------+   2   +--------------+
  LAN  <===> |              | <===> |   1/10G      |
             |  Redirector  |       |   Ethernet   |
  LAN  <===> |    Switch    | <===> |   Adapter    |
         1   +--------------+   3   +--------------+

  Drop Rule
  Discard incoming packets matching the filter
  on 'rule_port'

  Redirect Rule
  Divert incoming packets matching the filter
  on 'rule_port' to 'rule_target_port'.

  Mirror Rule
  Copy incoming packets matching the filter
  on 'rule_port' to 'rule_target_port'. The original
  packet will continue its journey (i.e. packet are
  actually duplicated)
*/

typedef enum {
  drop_rule,
  redirect_rule,
  mirror_rule
} silicom_redirector_rule_type;

typedef struct {
  silicom_redirector_rule_type rule_type;
  u_int8_t rule_port; /* Port on which the rule is defined */
  u_int8_t rule_target_port; /* Target port (ignored for drop rules) */
  u_int16_t vlan_id_low, vlan_id_high;
  u_int8_t l3_proto;
  ip_addr src_addr, dst_addr;
  u_int32_t src_mask, dst_mask;
  u_int16_t src_port_low, src_port_high;
  u_int16_t dst_port_low, dst_port_high;
} __attribute__((packed))
silicom_redirector_hw_rule;

typedef enum {
  default_pass,
  default_drop
} generic_default_action_type;

typedef enum {
  flow_drop_rule,
  flow_mark_rule,
  flow_pass_rule,
  flow_steer_rule,
  flow_unlearn_rule
} generic_flow_rule_action_type;

/* Deprecated (Accolade) */
typedef struct {
  generic_flow_rule_action_type action;
  u_int64_t flow_id; /* flow id from flow metadata */
  u_int32_t thread; /* id of the thread setting the rule - deprecated */
} __attribute__((packed))
generic_flow_id_hw_rule;

/* Mellanox, Napatech */
typedef struct {
  generic_flow_rule_action_type action;
  ip_addr src_ip;
  ip_addr dst_ip;
  ip_addr src_ip_mask; /* deprecated */
  ip_addr dst_ip_mask; /* deprecated */
  u_int16_t src_port;
  u_int16_t dst_port;
  u_int16_t vlan_id;
  u_int8_t ip_version;
  u_int8_t protocol;
  u_int8_t interface; /* from extended_hdr.if_index */
  u_int8_t queue_id; /* with action == flow_steer_rule */
  u_int64_t flow_id; /* Napatech Flow Manager only */
} __attribute__((packed))
generic_flow_tuple_hw_rule;

typedef enum {
  intel_82599_five_tuple_rule,
  intel_82599_perfect_filter_rule,
  silicom_redirector_rule,
  generic_flow_id_rule,
  generic_flow_tuple_rule,
} hw_filtering_rule_type;

typedef struct {
  hw_filtering_rule_type rule_family_type;

  /* FILTERING_RULE_AUTO_RULE_ID to auto generate a rule ID
   * Supported by Mellanox */
  u_int16_t rule_id;

  /* Rule priority (when supported by the adapter)
   * Supported by Mellanox (0..2) */
  u_int16_t priority;

  union {
    intel_82599_five_tuple_filter_hw_rule five_tuple_rule; /* Intel ixgbe */
    intel_82599_perfect_filter_hw_rule perfect_rule; /* Intel ixgbe */
    silicom_redirector_hw_rule redirector_rule; /* Silicom Redirector (Intel) */
    generic_flow_id_hw_rule flow_id_rule;
    generic_flow_tuple_hw_rule flow_tuple_rule; /* Mellanox */
  } rule_family;
} __attribute__((packed))
hw_filtering_rule;

#define MAGIC_HW_FILTERING_RULE_REQUEST  0x29010020 /* deprecated? */

#ifdef __KERNEL__

#define ETHTOOL_PFRING_SRXFTCHECK 0x10000000
#define ETHTOOL_PFRING_SRXFTRLDEL 0x10000031
#define ETHTOOL_PFRING_SRXFTRLINS 0x10000032

#if defined(I82599_HW_FILTERING_SUPPORT) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,40))
#define        FLOW_EXT 0x80000000
union _kcompat_ethtool_flow_union {
  struct ethtool_tcpip4_spec                tcp_ip4_spec;
  struct ethtool_usrip4_spec                usr_ip4_spec;
  __u8                                        hdata[60];
};
struct _kcompat_ethtool_flow_ext {
  __be16        vlan_etype;
  __be16        vlan_tci;
  __be32        data[2];
};
struct _kcompat_ethtool_rx_flow_spec {
  __u32                flow_type;
  union _kcompat_ethtool_flow_union h_u;
  struct _kcompat_ethtool_flow_ext h_ext;
  union _kcompat_ethtool_flow_union m_u;
  struct _kcompat_ethtool_flow_ext m_ext;
  __u64                ring_cookie;
  __u32                location;
};
#define ethtool_rx_flow_spec _kcompat_ethtool_rx_flow_spec
#endif /* defined(I82599_HW_FILTERING_SUPPORT) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,40)) */

#endif /* __KERNEL__ */

typedef enum {
  add_hw_rule,
  remove_hw_rule
} hw_filtering_rule_command;

/* *********************************** */

struct pfring_timespec {
  u_int32_t tv_sec;
  u_int32_t tv_nsec;
} __attribute__((packed));

/* *********************************** */

/* Used by PF_RING_FLOW_OFFLOAD (Napatech Flow Manager) */
typedef struct {
  u_int64_t flow_id;

#if 0
  u_int16_t vlan_id;

  u_int8_t ip_version;
  u_int8_t l4_protocol;

  u_int8_t tos;
  u_int8_t tcp_flags;

  ip_addr src_ip;
  ip_addr dst_ip;

  u_int16_t src_port;
  u_int16_t dst_port;
#endif

#define PF_RING_FLOW_UPDATE_CAUSE_SW       0
#define PF_RING_FLOW_UPDATE_CAUSE_TIMEOUT  1
#define PF_RING_FLOW_UPDATE_CAUSE_TCP_TERM 2
#define PF_RING_FLOW_UPDATE_CAUSE_PERIODIC 3
#define PF_RING_FLOW_UPDATE_CAUSE_PROBE    4
#define PF_RING_FLOW_UPDATE_CAUSE_UNKNOWN  5
  u_int8_t cause;
  u_int8_t padding_0;
  u_int16_t padding_1;

  u_int16_t flags_out;
  u_int16_t flags_in;

  u_int32_t packets_out;
  u_int32_t packets_in;
  u_int64_t bytes_out;
  u_int64_t bytes_in;

  struct pfring_timespec last_seen;
} __attribute__((packed))
pfring_flow_update;

/* *********************************** */

/* Deprecated (Accolade) */
typedef struct {
  u_int32_t flow_id;

  u_int8_t ip_version;
  u_int8_t l4_protocol;

  u_int8_t tos;
  u_int8_t tcp_flags;

  ip_addr src_ip;
  ip_addr dst_ip;

  u_int16_t vlan_id;
  u_int8_t start_of_flow;
  u_int8_t reserved; /* padding */

  u_int16_t src_port;
  u_int16_t dst_port;

  u_int32_t fwd_packets;
  u_int32_t rev_packets;
  u_int64_t fwd_bytes;
  u_int64_t rev_bytes;

  struct pfring_timespec fwd_ts_first;
  struct pfring_timespec fwd_ts_last;
  struct pfring_timespec rev_ts_first;
  struct pfring_timespec rev_ts_last;
} __attribute__((packed))
generic_flow_update;

/* Deprecated (Accolade) */
typedef struct {
  generic_flow_rule_action_type action;
  u_int32_t flow_id;
} __attribute__((packed))
generic_flow_feedback;

/* *********************************** */

extern struct pf_ring_socket *pfr; /* Forward */

/* *********************************** */

typedef int (*five_tuple_rule_handler)(struct pf_ring_socket *pfr,
                                       hw_filtering_rule *rule,
                                       hw_filtering_rule_command request);
typedef int (*perfect_filter_hw_rule_handler)(struct pf_ring_socket *pfr,
                                              hw_filtering_rule *rule,
                                              hw_filtering_rule_command request);

typedef struct {
  five_tuple_rule_handler five_tuple_handler;
  perfect_filter_hw_rule_handler perfect_filter_handler;
} __attribute__((packed))
hw_filtering_device_handler;

/* *********************************** */

/* Hash size used for precise packet matching */
#define DEFAULT_RING_HASH_SIZE     4096

/*
 * The hashtable contains only perfect matches: no
 * wildacards or so are accepted. (bidirectional)
 */
typedef struct {
  u_int16_t rule_id; /* Future use */
  u_int16_t vlan_id;
  u_int8_t ip_version;
  u_int8_t proto; /* Layer 3 protocol */
  ip_addr host_peer_a, host_peer_b;
  u_int16_t port_peer_a, port_peer_b;

  rule_action_behaviour rule_action; /* What to do in case of match */
  char reflector_device_name[REFLECTOR_NAME_LEN];

  filtering_internals internals;   /* PF_RING internal fields */
} __attribute__((packed))
hash_filtering_rule;

typedef struct {
  u_int64_t match;
  u_int64_t filtered;
  u_int64_t match_forward;
  u_int32_t inactivity; /* sec */
} __attribute__((packed))
hash_filtering_rule_stats;

/* ************************************************* */

typedef struct _sw_filtering_hash_bucket {
  hash_filtering_rule           rule;
  u_int64_t                     match;         /* number of packets matching the rule */
  u_int64_t                     filtered;      /* number of packets filtered by the rule */
  u_int64_t                     match_forward; /* number of packets sampled by the rule (equivalent to match minus filtered) */
  struct _sw_filtering_hash_bucket *next;
} __attribute__((packed))
sw_filtering_hash_bucket;

/* *********************************** */

#define RING_MIN_SLOT_SIZE    (60+sizeof(struct pfring_pkthdr))
#define RING_MAX_SLOT_SIZE    (1514+sizeof(struct pfring_pkthdr))

#if !defined(__cplusplus)

#define min_val(a,b) ((a < b) ? a : b)
#define max_val(a,b) ((a > b) ? a : b)

#endif

/* *********************************** */

/* False sharing reference: http://en.wikipedia.org/wiki/False_sharing */

typedef struct flowSlotInfo {
  /* first page, managed by kernel */
  u_int16_t version, sample_rate;
  u_int32_t min_num_slots, slot_len, data_len;
  u_int64_t tot_mem;
  volatile u_int64_t insert_off;
  u_int64_t kernel_remove_off;
  u_int64_t tot_pkts, tot_lost;
  volatile u_int64_t tot_insert;
  u_int64_t kernel_tot_read;
  u_int64_t tot_fwd_ok, tot_fwd_notok;
  u_int64_t good_pkt_sent, pkt_send_error;
  /* <-- more than 64 bytes here, should be enough to avoid some L1 VIVT coherence issues (32 ~ 64bytes lines) */

  char padding[128-104];

  /* <-- 128 bytes here, should be enough to avoid false sharing in most L2 (64 ~ 128bytes lines) */
  char k_padding[4096-128];
  /* <-- 4096 bytes here, to get a page aligned block writable by kernel side only */

  /* second page, managed by userland */
  volatile u_int64_t tot_read;
  volatile u_int64_t remove_off /* managed by userland */;
  char u_padding[4096-16];
  /* <-- 8192 bytes here, to get a page aligned block writable by userland only */
} __attribute__((packed))
FlowSlotInfo;

/* **************************************** */

#ifdef __KERNEL__
FlowSlotInfo *getRingPtr(void);
int allocateRing(char *deviceName, u_int32_t numSlots, u_int32_t bucketLen, u_int32_t sampleRate);
unsigned int pollRing(struct file *fp, struct poll_table_struct * wait);
void deallocateRing(void);
#endif /* __KERNEL__ */

/* *********************************** */

#define PF_RING          27      /* (0x1b) Packet Ring */
#define SOCK_RING        PF_RING

/* ioctl() */
#define SIORINGPOLL      0x8888

/* ************************************************* */

#ifdef __KERNEL__
struct ring_sock {
  struct sock           sk; /* It MUST be the first element */
  struct pf_ring_socket *pf_ring_sk;
};
#endif

/* *********************************** */

/* ZC driver API - data structures */

typedef int (*zc_dev_wait_packet)(void *rx_adapter, int mode);
typedef int (*zc_dev_notify)(void *rx_adapter, void *tx_adapter, u_int8_t device_in_use);
typedef int (*zc_dev_set_time)(void *rx_adapter, u_int64_t time_ns);
typedef int (*zc_dev_adjust_time)(void *rx_adapter, int64_t offset_ns);
typedef int (*zc_dev_get_tx_time)(void *tx_adapter, u_int64_t *time_ns);
typedef int (*zc_dev_control_queue)(void *rx_adapter, u_int8_t enable);
typedef int (*zc_dev_get_stats)(void *rx_adapter, u_int64_t *rx_missed);

typedef struct {
  zc_dev_wait_packet wait_packet;
  zc_dev_notify usage_notification;
  zc_dev_set_time set_time;
  zc_dev_adjust_time adjust_time;
  zc_dev_get_tx_time get_tx_time;
  zc_dev_control_queue control_queue;
  zc_dev_get_stats get_stats;
} __attribute__((packed))
zc_dev_callbacks;

typedef enum {
  add_device_mapping = 0,
  remove_device_mapping
} zc_dev_operation;

/* IMPORTANT NOTE
 * add new family types ALWAYS at the end
 * (i.e. append) of this datatype */
typedef enum {
  intel_e1000e = 0,
  intel_igb,
  intel_ixgbe,
  intel_ixgbe_82598,
  intel_ixgbe_82599,
  intel_igb_ts,
  intel_e1000,
  intel_ixgbe_82599_ts,
  intel_i40e,
  intel_ixgbe_vf,
  intel_ixgbe_x550,
  intel_ice,
  intel_i40e_ice_vf
} zc_dev_model;

typedef struct {
  u_int32_t packet_memory_num_slots;
  u_int32_t packet_memory_slot_len;
  u_int32_t descr_packet_memory_tot_len;
  u_int16_t registers_index;
  u_int16_t stats_index;
  u_int32_t vector;
  u_int32_t num_queues;
} __attribute__((packed))
zc_dev_ring_info;

/* ************************************************* */

typedef struct {
  zc_dev_ring_info rx;
  zc_dev_ring_info tx;
  u_int32_t phys_card_memory_len;
  zc_dev_model device_model;
} __attribute__((packed))
zc_memory_info;

typedef struct {
  zc_memory_info mem_info;
  u_int16_t channel_id;
  void *rx_descr_packet_memory; /* Invalid in userland */
  void *tx_descr_packet_memory; /* Invalid in userland */
  char *phys_card_memory;       /* Invalid in userland */
  struct net_device *dev;       /* Invalid in userland */
  struct device *hwdev;         /* Invalid in userland */
  u_char device_address[6];
#ifdef __KERNEL__
  wait_queue_head_t *packet_waitqueue;
#else
  void *packet_waitqueue;
#endif
  u_int8_t *interrupt_received;
  u_int8_t in_use;
  void *rx_adapter;
  void *tx_adapter;
  zc_dev_callbacks callbacks;
} __attribute__((packed))
zc_dev_info;

#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif

typedef struct {
  zc_dev_operation operation;
  char device_name[IFNAMSIZ];
  int32_t channel_id;
  zc_dev_model device_model; /* out */
} __attribute__((packed))
zc_dev_mapping;

/* ************************************************* */

#define RING_ANY_CHANNEL          ((u_int64_t)-1)
#define MAX_NUM_RX_CHANNELS       64 /* channel_id_mask is a 64 bit mask */
#define UNKNOWN_NUM_RX_CHANNELS   1

#define RING_ANY_VLAN             ((u_int16_t)0xFFFF)
#define RING_NO_VLAN              ((u_int16_t)0)

/* ************************************************* */

typedef enum {
  cluster_per_flow = 0,              /* 6-tuple: <src ip, src port, dst ip, dst port, proto, vlan>  */
  cluster_round_robin,
  cluster_per_flow_2_tuple,          /* 2-tuple: <src ip,           dst ip                       >  */
  cluster_per_flow_4_tuple,          /* 4-tuple: <src ip, src port, dst ip, dst port             >  */
  cluster_per_flow_5_tuple,          /* 5-tuple: <src ip, src port, dst ip, dst port, proto      >  */
  cluster_per_flow_tcp_5_tuple,      /* 5-tuple only with TCP, 2 tuple with all other protos        */
  /* same as above, computing on tunnel content when present */
  cluster_per_inner_flow,            /* 6-tuple: <src ip, src port, dst ip, dst port, proto, vlan>  */
  cluster_per_inner_flow_2_tuple,    /* 2-tuple: <src ip,           dst ip                       >  */
  cluster_per_inner_flow_4_tuple,    /* 4-tuple: <src ip, src port, dst ip, dst port             >  */
  cluster_per_inner_flow_5_tuple,    /* 5-tuple: <src ip, src port, dst ip, dst port, proto      >  */
  cluster_per_inner_flow_tcp_5_tuple,/* 5-tuple only with TCP, 2 tuple with all other protos        */
  /* new types, for L2-only protocols */
  cluster_per_flow_ip_5_tuple,       /* 5-tuple only with IP, 2 tuple with non-IP <src mac, dst mac> */
  cluster_per_inner_flow_ip_5_tuple, /* 5-tuple only with IP, 2 tuple with non-IP <src mac, dst mac> */
  cluster_per_flow_ip_with_dup_tuple, /* 1-tuple: <src ip> and <dst ip> with duplication              */
  cluster_per_flow_ip_with_dup_tuple_ext /* 1-tuple: <src ip> and <dst ip> with duplication, fan-out on hash(src ip) == hash (dst ip) and port != 443 */
} cluster_type;

#define MAX_CLUSTER_TYPE_ID cluster_per_flow_ip_with_dup_tuple_ext

struct add_to_cluster {
  u_int16_t cluster_id;
  u_int16_t queue_id;
#define CLUSTER_OPTION_RELAXED_DISTRIBUTION (1<<0)
  u_int32_t options;
  cluster_type the_type;
} __attribute__((packed));

typedef enum {
  standard_nic_family = 0, /* No Hw Filtering */
  intel_82599_family
} pfring_device_type;

typedef struct {
  char device_name[IFNAMSIZ];
  pfring_device_type device_type;

  /* Entry in the /proc filesystem */
  struct proc_dir_entry *proc_entry;
} __attribute__((packed))
virtual_filtering_device_info;

/* ************************************************* */

struct create_cluster_referee_info {
  u_int32_t cluster_id;
  u_int32_t recovered; /* fresh or recovered */
} __attribute__((packed));

struct public_cluster_object_info {
  u_int32_t cluster_id;
  u_int32_t object_type;
  u_int32_t object_id;
} __attribute__((packed));

struct lock_cluster_object_info {
  u_int32_t cluster_id;
  u_int32_t object_type;
  u_int32_t object_id;
  u_int32_t lock_mask;
  u_int32_t reserved; /* used by VMs to pass the op */
  u_int32_t locked_mask; /* out */
} __attribute__((packed));

/* ************************************************* */

typedef enum {
  cluster_slave  = 0,
  cluster_master = 1
} cluster_client_type;

/* ************************************************* */

#ifdef __KERNEL__

#if(LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
#ifndef netdev_notifier_info_to_dev
#define netdev_notifier_info_to_dev(a) ((struct net_device*)a)
#endif
#endif

/*
 * A ring cluster is used group together rings used by various applications
 * so that they look, from the PF_RING point of view, as a single ring.
 * This means that developers can use clusters for sharing packets across
 * applications using various policies as specified in the hashing_mode
 * parameter.
 */
struct ring_cluster {
  u_int32_t      cluster_id; /* 0 = no cluster */
  u_int16_t      num_cluster_queues;
  u_int16_t      max_queue_index;
  u_int16_t      hashing_id;
  u_int8_t       relaxed_distribution;
  u_int8_t       padding;
  cluster_type   hashing_mode;
  struct sock    *sk[MAX_CLUSTER_QUEUES];
};

/*
 * Linked-list of ring clusters
 */
typedef struct {
  struct ring_cluster cluster;
  struct list_head list;
} ring_cluster_element;

#define MAX_NUM_ZC_BOUND_SOCKETS MAX_NUM_RING_SOCKETS

typedef struct {
  u8 num_bound_sockets;
  zc_dev_info zc_dev;
  struct list_head list;
  /*
    In the ZC world only one application can open and enable the
    device@channel per direction. The array below is used to keep
    pointers to the sockets bound to device@channel.
    No more than one socket can be enabled for RX and one for TX.
  */
  struct pf_ring_socket *bound_sockets[MAX_NUM_ZC_BOUND_SOCKETS];
  spinlock_t lock;
} zc_dev_list;

#define MAX_NUM_IFINDEX 0x7FFFFFFF
#define MAX_NUM_DEV_IDX 1024

#define ANY_IFINDEX  (MAX_NUM_IFINDEX-1)
#define NONE_IFINDEX (MAX_NUM_IFINDEX-2)

/*
 * Linked-list of virtual filtering devices
 */
typedef struct {
  virtual_filtering_device_info info;
  struct list_head list;
} virtual_filtering_device_element;

/* ************************************************* */

typedef struct {
  u_int8_t set;
  u_int8_t direct_mapping;
  int32_t ifindex;
} ifindex_map_item;

/* ************************************************* */

typedef struct {
  struct net_device *dev;

  /* Note: we keep device_name here for a couple of reasons:
   * 1. some device types might NOT have a net_device handler
   * 2. when a device name changes we need to remember the old name */
  char device_name[IFNAMSIZ];

  pfring_device_type device_type; /* Device Type */
  int32_t dev_index;

  u_int8_t do_not_remove_promisc; /* promisc was set before any socket */
  atomic_t promisc_users; /* number of rings with promisc set bound to this device */

  /* Entry in the /proc filesystem */
  struct proc_dir_entry *proc_entry;
  struct proc_dir_entry *proc_info_entry;

  /* ZC */
  u_int8_t is_zc_device;
  zc_dev_model zc_dev_model;
  u_int32_t num_zc_dev_rx_queues; /* 0 for non ZC devices */
  u_int32_t num_zc_rx_slots;
  u_int32_t num_zc_tx_slots;

  /* Hardware Filters */
  struct {
    u_int16_t num_filters;
    hw_filtering_device_handler filter_handlers;
  } hw_filters;

  struct list_head device_list;
} pf_ring_device;

/* ************************************************* */

struct dma_memory_info {
  u_int32_t num_chunks, chunk_len;
  u_int32_t num_slots,  slot_len;
  unsigned long *virtual_addr;  /* chunks pointers */
  u_int64_t     *dma_addr;      /* per-slot DMA addresses */
  struct device *hwdev;         /* dev for DMA mapping */
};

/* ************************************************* */

typedef struct {
  u_int32_t object_type;
  u_int32_t object_id;
  u_int32_t lock_bitmap;

  struct list_head list;
} cluster_object;

struct cluster_referee {
  u_int32_t id;
  u_int32_t users;
  u_int8_t  master_running;
  struct list_head objects_list;

  struct list_head list;
};

/* ************************************************* */

typedef u_int32_t (*do_rehash_rss)(struct sk_buff *skb, struct pfring_pkthdr *hdr);

/* ************************************************* */

#define NUM_FRAGMENTS_HASH_SLOTS                          4096
#define MAX_CLUSTER_FRAGMENTS_LEN   8*NUM_FRAGMENTS_HASH_SLOTS

struct hash_fragment_node {
  /* Key */
  u_int32_t ipv4_src_host, ipv4_dst_host;
  u_int16_t ip_fragment_id;

  /* Value */
  u_int8_t cluster_app_id; /* Identifier of the app where the main fragment has been placed */

  /* Expire */
  unsigned long expire_jiffies; /* Time at which this entry will be expired */

  /* collision list */
  struct list_head frag_list;
};

/* ************************************************* */

/*
 * Ring options
 */
struct pf_ring_socket {
  struct mutex ring_config_lock;

  u_int8_t ring_active, ring_shutdown, num_rx_channels, num_bound_devices;
  pf_ring_device *ring_dev;

  /* last device set with bind, needed to heck channels when multiple
   * devices are used with quick-mode */
  pf_ring_device *last_bind_dev;

  DECLARE_BITMAP(pf_dev_mask, MAX_NUM_DEV_IDX /* bits */);
  int ring_pid;
  u_int32_t ring_id;
  packet_direction direction; /* Specify the capture direction for packets */
  socket_mode mode; /* Specify the link direction to enable (RX, TX, both) */
  pkt_header_len header_len;
  u_int8_t stack_injection_mode;
  u_int8_t discard_injected_pkts;
  u_int8_t promisc_enabled;
  u_int8_t __padding;

  struct sock *sk;

  char appl_name[64]; /* String that identifies the application bound to the socket */

  /* /proc */
  char sock_proc_name[64];       /* /proc/net/pf_ring/<sock_proc_name>             */
  char sock_proc_stats_name[64]; /* /proc/net/pf_ring/stats/<sock_proc_stats_name> */
  char statsString[1024];
  char custom_bound_device_name[32];

  /* Poll Watermark */
  u_int32_t num_poll_calls;
  u_int16_t poll_num_pkts_watermark;
  u_int16_t poll_watermark_timeout;
  u_long    queue_nonempty_timestamp;

  /* Master Ring */
  struct pf_ring_socket *master_ring;

  /* Used to transmit packets after they have been received
     from user space */
  struct {
    u_int8_t enable_tx_with_bounce;
    spinlock_t consume_tx_packets_lock;
    int32_t last_tx_dev_idx;
    struct net_device *last_tx_dev;
  } tx;

  /* ZC (Direct NIC Access) */
  zc_dev_mapping zc_mapping;
  zc_dev_info *zc_dev;
  zc_dev_list *zc_device_entry;

  /* Extra DMA memory */
  struct dma_memory_info *extra_dma_memory;

  /* Cluster */
  u_int32_t cluster_id /* 0 = no cluster */;

  /* Channel */
  int64_t channel_id_mask;  /* -1 = any channel */
  u_int16_t num_channels_per_ring;

  /* rehash rss function pointer */
  do_rehash_rss rehash_rss;

  /* Ring Slots */
  u_char *ring_memory;
  u_int16_t slot_header_len;
  u_int32_t bucket_len, slot_tot_mem;
  FlowSlotInfo *slots_info; /* Points to ring_memory */
  u_char *ring_slots;       /* Points to ring_memory+sizeof(FlowSlotInfo) */

  /* Packet Sampling */
  u_int32_t sample_rate;
  u_int32_t pkts_to_sample;
  u_int32_t sample_rnd_shift;

  /* Virtual Filtering Device */
  virtual_filtering_device_element *v_filtering_dev;

  /* VLAN ID */
  u_int16_t vlan_id; /* 0 = all VLANs are accepted */

  int32_t bpfFilter; /* bool */

  /* Sw Filtering Rules - default policy */
  u_int8_t sw_filtering_rules_default_accept_policy; /* 1=default policy is accept, drop otherwise */

  /* Sw Filtering Rules - hash */
  sw_filtering_hash_bucket **sw_filtering_hash;
  u_int64_t sw_filtering_hash_match;
  u_int64_t sw_filtering_hash_miss;
  u_int64_t sw_filtering_hash_filtered;
  u_int32_t num_sw_filtering_hash;

  /* Sw Filtering Rules - wildcard */
  u_int32_t num_sw_filtering_rules;
  struct list_head sw_filtering_rules;

  /* Hw Filtering Rules */
  u_int16_t num_hw_filtering_rules;
  struct list_head hw_filtering_rules;

  /* Filtering sampling */
  u_int32_t filtering_sample_rate;
  u_int32_t filtering_sampling_size;

  /* Locks */
  atomic_t num_ring_users;
  wait_queue_head_t ring_slots_waitqueue;
  spinlock_t ring_index_lock;
  rwlock_t ring_rules_lock;

  /* Indexes (Internal) */
  u_int32_t insert_page_id, insert_slot_id;

  /* Kernel consumer */
  char *kernel_consumer_options, *kernel_consumer_private;

  /* Userspace cluster (ZC) */
  struct cluster_referee *cluster_referee;
  cluster_client_type cluster_role;
};

/* **************************************** */

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0)
#define SINGLE_PROT_HOOK
#endif

typedef struct {
  u_int32_t magic;

  struct net *net;

#ifndef SINGLE_PROT_HOOK
  struct packet_type prot_hook;
#endif

  /* /proc entry for ring module */
  struct proc_dir_entry *proc;
  struct proc_dir_entry *proc_dir;
  struct proc_dir_entry *proc_dev_dir;
  struct proc_dir_entry *proc_stats_dir;

  /* Map ifindex to pf device idx (used for num_rings_per_device) */
  ifindex_map_item ifindex_map[MAX_NUM_DEV_IDX];

  /* Keep track of number of rings per device (plus any) */
  u_int8_t num_rings_per_device[MAX_NUM_DEV_IDX];
  u_int32_t num_any_rings;
} pf_ring_net;

/* **************************************** */

#define MAX_NUM_PATTERN   32

typedef struct {
  filtering_rule rule;

#ifdef CONFIG_TEXTSEARCH
  struct ts_config *pattern[MAX_NUM_PATTERN];
#endif
  struct list_head list;
} sw_filtering_rule_element;

typedef struct {
  hw_filtering_rule rule;
  struct list_head list;
} hw_filtering_rule_element;

/* **************************************** */

/* Exported functions - used by drivers */

int pf_ring_skb_ring_handler(struct sk_buff *skb,
                             u_int8_t recv_packet,
                             u_int8_t real_skb /* 1=real skb, 0=faked skb */,
                             int32_t channel_id,
                             u_int32_t num_rx_channels);

/* ZC driver API */

void pf_ring_zc_dev_handler(zc_dev_operation operation,
                            zc_dev_callbacks *callbacks,
                            zc_dev_ring_info *rx_info,
                            zc_dev_ring_info *tx_info,
                            void *rx_descr_packet_memory,
                            void *tx_descr_packet_memory,
                            void *phys_card_memory,
                            u_int32_t phys_card_memory_len,
                            u_int32_t channel_id,
                            struct net_device *dev,
                            struct device *hwdev,
                            zc_dev_model device_model,
                            u_char *device_address,
                            wait_queue_head_t *packet_waitqueue,
                            u_int8_t *interrupt_received,
                            void *rx_adapter_ptr,
                            void *tx_adapter_ptr);

#endif /* __KERNEL__  */

/* *********************************** */

#endif /* __RING_H */
