blob: 4d1bc3dd71bacf9a9d0ba7f52a353c53a8e08246 [file] [log] [blame]
/*
* ********************************************************************************
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
**********************************************************************************
*/
#ifndef __NSS_IPSECMGR_PRIV_H
#define __NSS_IPSECMGR_PRIV_H
#include <net/ipv6.h>
#include <nss_api_if.h>
#include <nss_ipsec.h>
#include <nss_ipsecmgr.h>
#define NSS_IPSECMGR_DEBUG_LVL_ERROR 1 /**< Turn on debug for an error. */
#define NSS_IPSECMGR_DEBUG_LVL_WARN 2 /**< Turn on debug for a warning. */
#define NSS_IPSECMGR_DEBUG_LVL_INFO 3 /**< Turn on debug for information. */
#define NSS_IPSECMGR_DEBUG_LVL_TRACE 4 /**< Turn on debug for trace. */
#define nss_ipsecmgr_info_always(s, ...) pr_info("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
#define nss_ipsecmgr_error(s, ...) do { \
if (net_ratelimit()) { \
pr_alert("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
#define nss_ipsecmgr_warn(s, ...) do { \
if (net_ratelimit()) { \
pr_warn("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
#if defined(CONFIG_DYNAMIC_DEBUG)
/*
* Compile messages for dynamic enable/disable
*/
#define nss_ipsecmgr_info(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
#define nss_ipsecmgr_trace(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
#else
/*
* Statically compile messages at different levels
*/
#define nss_ipsecmgr_info(s, ...) { \
if (NSS_IPSECMGR_DEBUG_LEVEL > NSS_IPSECMGR_DEBUG_LVL_INFO) { \
pr_notice("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__); \
} \
}
#define nss_ipsecmgr_trace(s, ...) { \
if (NSS_IPSECMGR_DEBUG_LEVEL > NSS_IPSECMGR_DEBUG_LVL_TRACE) { \
pr_info("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__); \
} \
}
#endif /* !CONFIG_DYNAMIC_DEBUG */
#define NSS_IPSECMGR_MAX_KEY_NAME 64 /* bytes */
#define NSS_IPSECMGR_MAX_KEY_WORDS 16 /* word */
#define NSS_IPSECMGR_MAX_KEY_BYTES (NSS_IPSECMGR_MAX_KEY_WORDS * sizeof(uint32_t))
#define NSS_IPSECMGR_MAX_KEY_BITS (NSS_IPSECMGR_MAX_KEY_WORDS * sizeof(uint32_t) * BITS_PER_BYTE)
#define NSS_IPSECMGR_CHK_POW2(x) (__builtin_constant_p(x) && !(~(x - 1) & (x >> 1)))
#define NSS_IPSECMGR_MAX_NAME (NSS_IPSECMGR_MAX_KEY_NAME + 64)
#define NSS_IPSECMGR_MAX_SA NSS_CRYPTO_MAX_IDXS /* Max SAs */
#if (~(NSS_IPSECMGR_MAX_SA - 1) & (NSS_IPSEC_MAX_SA >> 1))
#error "NSS_IPSECMGR_MAX_SA is not a power of 2"
#endif
#define NSS_IPSECMGR_MAX_FLOW 256 /* Max flows */
#if (~(NSS_IPSECMGR_MAX_FLOW - 1) & (NSS_IPSECMGR_MAX_FLOW >> 1))
#error "NSS_IPSECMGR_MAX_FLOW is not a power of 2"
#endif
#define NSS_IPSECMGR_MAX_SUBNET 16 /* Max subnets */
#if (~(NSS_IPSECMGR_MAX_SUBNET - 1) & (NSS_IPSECMGR_MAX_SUBNET >> 1))
#error "NSS_IPSECMGR_MAX_SUBNET is not a power of 2"
#endif
#define NSS_IPSECMGR_MAX_NETMASK 128 /* Max subnets */
#if (~(NSS_IPSECMGR_MAX_NETMASK - 1) & (NSS_IPSECMGR_MAX_NETMASK >> 1))
#error "NSS_IPSECMGR_MAX_NETMASK is not a power of 2"
#endif
#define NSS_IPSECMGR_NETMASK_BITMAP BITS_TO_LONGS(NSS_IPSECMGR_MAX_NETMASK)
#define NSS_IPSECMGR_GENMASK(hi, lo) ((~0 >> (31 - hi)) << lo)
#define NSS_IPSECMGR_MAX_BUF_SZ 2048
#define NSS_IPSECMGR_PROTO_NEXT_HDR_ANY 0xff
#define NSS_IPSECMGR_V6_SUBNET_BITS (sizeof(uint32_t) * 2 * BITS_PER_BYTE)
#define NSS_IPSECMGR_SA_STATS_SIZE 512
#define NSS_IPSECMGR_SUBNET_STATS_SIZE 100
#define NSS_IPSECMGR_MSG_SYNC_TIMEOUT_MSECS 2000
#define NSS_IPSECMGR_MSG_SYNC_TIMEOUT_TICKS msecs_to_jiffies(NSS_IPSECMGR_MSG_SYNC_TIMEOUT_MSECS)
#define NSS_IPSECMGR_PER_FLOW_STATS_SIZE 200
#define NSS_IPSECMGR_PER_FLOW_BUF_SIZE 500
#define NSS_IPSECMGR_PER_FLOW_BUF_SRC_IP_SIZE 100
#define NSS_IPSECMGR_PER_FLOW_BUF_DST_IP_SIZE 100
#define NSS_IPSECMGR_PER_FLOW_BUF_TYPE_SIZE 100
#define NSS_IPSECMGR_BITS_PER_WORD (sizeof(uint32_t) * BITS_PER_BYTE)
#define NSS_IPSECMGR_BITS2WORD(p) ((p) / NSS_IPSECMGR_BITS_PER_WORD)
#define NSS_IPSECMGR_DEFAULT_TUN_NAME "ipsecdummy"
#define NSS_IPSECMGR_ESP_TRAIL_SZ 2 /* esp trailer size */
#define NSS_IPSECMGR_ESP_PAD_SZ 14 /* maximum amount of padding */
struct nss_ipsecmgr_ref;
struct nss_ipsecmgr_key;
struct nss_ipsecmgr_priv;
/*
* IPsec manager key length for
* - SA entries
* - Flow entries
* - Subnet entries
*/
enum nss_ipsecmgr_key_len {
NSS_IPSECMGR_KEY_LEN_NONE = 0,
NSS_IPSECMGR_KEY_LEN_IPV4_SA = 4, /* 16 bytes */
NSS_IPSECMGR_KEY_LEN_IPV4_SUBNET = 2, /* 8 bytes */
NSS_IPSECMGR_KEY_LEN_IPV4_ENCAP_FLOW = 3, /* 12 bytes */
NSS_IPSECMGR_KEY_LEN_IPV4_DECAP_FLOW = 4, /* 16 bytes */
NSS_IPSECMGR_KEY_LEN_IPV6_SA = 10, /* 40 bytes */
NSS_IPSECMGR_KEY_LEN_IPV6_SUBNET = 5, /* 20 bytes */
NSS_IPSECMGR_KEY_LEN_IPV6_ENCAP_FLOW = 9, /* 36 bytes */
NSS_IPSECMGR_KEY_LEN_IPV6_DECAP_FLOW = 10, /* 40 bytes */
NSS_IPSECMGR_KEY_LEN_MAX = NSS_IPSECMGR_MAX_KEY_WORDS
};
/*
* IPsec manager key map for header fields to key elements
*/
enum nss_ipsecmgr_key_pos {
NSS_IPSECMGR_KEY_POS_IP_VER = 0, /* IP version, bits[0:7] */
NSS_IPSECMGR_KEY_POS_IP_PROTO = 8, /* IPv4 Proto, bits[8:15] */
NSS_IPSECMGR_KEY_POS_IPV4_DST = 32, /* IPv4 DST, bits[32:63] */
NSS_IPSECMGR_KEY_POS_IPV4_SRC = 64, /* IPv4 SIP, bits[64:95] */
NSS_IPSECMGR_KEY_POS_IPV4_ESP_SPI = 96, /* IPv4 ESP SPI, bits[96:127] */
NSS_IPSECMGR_KEY_POS_IPV6_DST = 32, /* IPv6 DST, bits[32:159] */
NSS_IPSECMGR_KEY_POS_IPV6_SRC = 160, /* IPv6 SIP, bits[160:287] */
NSS_IPSECMGR_KEY_POS_IPV6_ESP_SPI = 288, /* IPv6 ESP SPI, bits[288:319] */
};
/*
* bits to mask within a key_word data, min - 0 & max - 31
*/
enum nss_ipsecmgr_key_mask {
NSS_IPSECMGR_KEY_MASK_IP_VER = NSS_IPSECMGR_GENMASK(7, 0), /* IP version, #bits - 8 */
NSS_IPSECMGR_KEY_MASK_IP_PROTO = NSS_IPSECMGR_GENMASK(15, 8), /* IP protocol, #bits - 8 */
NSS_IPSECMGR_KEY_MASK_IPV4_DST = NSS_IPSECMGR_GENMASK(31, 0), /* IPv4 dst, #bits - 32 */
NSS_IPSECMGR_KEY_MASK_IPV4_SRC = NSS_IPSECMGR_GENMASK(31, 0), /* IPv4 src, #bits - 32 */
NSS_IPSECMGR_KEY_MASK_ESP_SPI = NSS_IPSECMGR_GENMASK(31, 0), /* ESP spi #bits - 32 */
};
struct nss_ipsecmgr_ref;
struct nss_ipsecmgr_key;
struct nss_ipsecmgr_priv;
typedef void (*nss_ipsecmgr_ref_update_t)(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_ref *ref, struct nss_ipsec_msg *nim);
typedef void (*nss_ipsecmgr_ref_free_t)(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_ref *ref);
typedef uint32_t (*nss_ipsecmgr_ref_overhead_t)(struct nss_ipsecmgr_ref *ref);
/*
* Key byte stream for lookup
*/
struct nss_ipsecmgr_key {
uint32_t data[NSS_IPSECMGR_MAX_KEY_WORDS]; /* Value N-bits */
uint32_t mask[NSS_IPSECMGR_MAX_KEY_WORDS]; /* Mask N-bits */
uint32_t len; /* Length of the key */
};
/*
* IPsec manager reference object
*/
struct nss_ipsecmgr_ref {
struct list_head head; /* parent "ref" */
struct list_head node; /* child "ref" */
uint32_t id; /* identifier */
struct nss_ipsecmgr_ref *parent; /* reference to parent */
nss_ipsecmgr_ref_update_t update; /* update function */
nss_ipsecmgr_ref_free_t free; /* free function */
nss_ipsecmgr_ref_overhead_t overhead; /* free function */
};
/*
* IPsec manager packets stats per SA
*/
struct nss_ipsecmgr_sa_pkt_stats {
uint64_t count;
uint64_t bytes;
uint64_t seq_num;
uint64_t window_max;
uint32_t window_size;
uint32_t no_headroom;
uint32_t no_tailroom;
uint32_t no_buf;
uint32_t fail_queue;
uint32_t fail_hash;
uint32_t fail_replay;
uint32_t fail_hash_cont; /* Continous fail hash count */
};
/*
* IPsec manager node stats
*/
struct nss_ipsecmgr_node_stats {
uint64_t enqueued; /* packets enqueued to the node */
uint64_t completed; /* packets processed by the node */
uint64_t linearized; /* linearized the packet */
uint64_t exceptioned; /* packets exception from NSS */
uint64_t fail_enqueue; /* packets failed to enqueue */
};
/*
* IPsec manager SA entry
*/
struct nss_ipsecmgr_sa_entry {
struct list_head node; /* list instance */
struct nss_ipsecmgr_ref ref; /* ref instance */
struct nss_ipsecmgr_key key; /* key instance */
uint32_t ifnum; /* SA interface */
uint32_t sa_overhead; /* max header + trailer added for SA */
bool esn_enabled; /* Is ESN enabled */
struct nss_ipsecmgr_sa_pkt_stats pkts; /* packets processed per SA */
struct nss_ipsecmgr_priv *priv; /* ipsecmgr private reference */
struct nss_ipsec_msg nim; /* ipsec message */
struct nss_ipsecmgr_sa sa_info; /* SA information */
uint32_t fail_hash_thresh; /* continous hash fail
threshold */
};
/*
* IPsec manager SA entry table
*/
struct nss_ipsecmgr_sa_db {
atomic_t num_entries; /* active entries in the entity */
struct list_head entries[NSS_IPSECMGR_MAX_SA];
};
/*
* IPsec manager subnet entry
*/
struct nss_ipsecmgr_subnet_entry {
struct list_head node; /* list node */
struct nss_ipsecmgr_ref ref; /* reference node */
struct nss_ipsecmgr_key key; /* key */
struct nss_ipsec_msg nim; /* IPsec message */
struct nss_ipsecmgr_priv *priv; /* ipsecmgr private reference */
};
/*
* IPsec netmask entry
*/
struct nss_ipsecmgr_netmask_entry {
uint32_t mask_bits; /* no. of bits in netmask */
uint32_t count; /* no. of subnets entries */
struct list_head subnets[NSS_IPSECMGR_MAX_SUBNET]; /* subnet database */
};
/*
* IPsec netmask database
*
* Note: this database is searched using bit positions present in bitmap
* where each bit in bitmap table represents a entry in the mask entry
* table
*/
struct nss_ipsecmgr_netmask_db {
atomic_t num_entries; /* active entries in the entity */
unsigned long bitmap[NSS_IPSECMGR_NETMASK_BITMAP]; /* netmask bitmap */
struct nss_ipsecmgr_netmask_entry *entries[NSS_IPSECMGR_MAX_NETMASK]; /* netmask entry database */
struct nss_ipsecmgr_netmask_entry *default_entry; /* default netmask */
};
/*
* IPsec manager flow data
*/
struct nss_ipsecmgr_flow_data {
uint32_t pkts_processed; /* packets processed for this flow */
uint32_t sa_overhead; /* max header + trailer added for SA */
};
/*
* IPsec manager flow entry
*/
struct nss_ipsecmgr_flow_entry {
struct list_head node; /* list object */
struct nss_ipsecmgr_ref ref; /* reference object */
struct nss_ipsecmgr_key key; /* key object */
struct nss_ipsecmgr_priv *priv; /* ipsecmgr private reference */
struct nss_ipsec_msg nim; /* IPsec message */
struct nss_ipsecmgr_flow_data data; /* Flow data */
};
/*
* Flow retry
*/
struct nss_ipsecmgr_flow_retry {
struct list_head node; /* retry list node */
struct nss_ipsecmgr_key key; /* flow key for lookup */
uint32_t ref_id; /* refernce object id */
};
/*
* IPsec manager flow database
*/
struct nss_ipsecmgr_flow_db {
atomic_t num_entries; /* active entries in the entity */
struct list_head entries[NSS_IPSECMGR_MAX_FLOW]; /* flow database */
};
/*
* IPsec manager callback database
*/
struct nss_ipsecmgr_callback_db {
atomic_t num_entries; /* number of callback(s) registered */
struct list_head entries; /* head of the first callback */
};
/*
* IPsec manager callback entry
*/
struct nss_ipsecmgr_callback_entry {
struct list_head node; /* list node */
int dev_index; /* device bound for callback */
void *app_data; /* callback context */
nss_ipsecmgr_data_cb_t data; /* data callback function */
nss_ipsecmgr_event_cb_t event; /* event callback function */
};
/*
* IPsec manager private context
*/
struct nss_ipsecmgr_priv {
struct net_device *dev; /* back pointer to tunnel device */
struct nss_ipsecmgr_callback_entry cb; /* callback entry instance */
atomic_t outer_dst_mtu; /* PMTU of outer tunnel DST */
struct rtnl_link_stats64 stats; /* stats of IPsec tunnel */
};
/*
* IPsec manager drv instance
*/
struct nss_ipsecmgr_drv {
struct dentry *dentry; /* Debugfs entry per ipsecmgr module. */
struct dentry *stats_dentry; /* Debugfs entry per stats dir */
struct net_device *ndev; /* IPsec dummy net device */
rwlock_t lock; /* lock for all DB operations */
struct nss_ipsecmgr_sa_db sa_db; /* SA database */
struct nss_ipsecmgr_netmask_db net_db; /* Subnet mask database */
struct nss_ipsecmgr_flow_db flow_db; /* flow database */
struct nss_ipsecmgr_callback_db cb_db; /* callback database */
struct completion complete; /* completion for flow stats nss msg */
int encap_ifnum; /* NSS encap interface */
int decap_ifnum; /* NSS decap interface */
int data_ifnum; /* NSS data interface */
struct nss_ctx_instance *nss_ctx; /* NSS context */
struct nss_ipsec_msg resp_nim; /* nim for per_flow stats */
struct semaphore sem; /* per flow semaphore lock */
atomic_t seq_num; /* per flow seq no */
struct nss_ipsecmgr_node_stats enc_stats; /* Encap node stats */
struct nss_ipsecmgr_node_stats dec_stats; /* Decap node stats */
};
/*
* nss_ipsecmgr_ref_is_updated()
* return true if reference objects id is updated
*/
static inline bool nss_ipsecmgr_ref_is_updated(struct nss_ipsecmgr_ref *ref)
{
return ref->id > 1;
}
/*
* nss_ipsecmgr_ref_get_id()
* return the reference object's id
*/
static inline uint32_t nss_ipsecmgr_ref_get_id(struct nss_ipsecmgr_ref *ref)
{
return ref->id;
}
/*
* nss_ipsecmgr_ref_is_empty()
* check if the SA has any reference
*/
static inline bool nss_ipsecmgr_ref_is_empty(struct nss_ipsecmgr_ref *ref)
{
return list_empty(&ref->head);
}
/*
* nss_ipsecmgr_key_reset()
* Reset the IPsec key
*/
static inline void nss_ipsecmgr_key_reset(struct nss_ipsecmgr_key *key)
{
memset(key, 0, sizeof(struct nss_ipsecmgr_key));
}
/*
* nss_ipsecmgr_key_read_8()
* read value & mask from the specified position
*/
static inline uint8_t nss_ipsecmgr_key_read_8(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint32_t data;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
data = key->data[idx];
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:7] */
return (uint8_t)data;
case 8: /* bits[8:15] */
return (uint8_t)(data >> 8);
case 16: /* bits[16:23] */
return (uint8_t)(data >> 16);
case 24: /* bits[24:31] */
return (uint8_t)(data >> 24);
default:
return 0;
}
}
/*
* nss_ipsecmgr_key_write_8()
* write 8-bit value from the specified position using mask
*/
static inline void nss_ipsecmgr_key_write_8(struct nss_ipsecmgr_key *key, uint8_t v, enum nss_ipsecmgr_key_pos p)
{
uint32_t *data, *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
data = &key->data[idx];
mask = &key->mask[idx];
/*
* clear data with mask, update data & save mask
*/
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:7] */
*data &= ~NSS_IPSECMGR_GENMASK(7, 0);
*data |= v;
*mask |= NSS_IPSECMGR_GENMASK(7, 0);
break;
case 8: /* bits[8:15] */
*data &= ~NSS_IPSECMGR_GENMASK(15, 8);
*data |= (v << 8);
*mask |= NSS_IPSECMGR_GENMASK(15, 8);
break;
case 16: /* bits[16:23] */
*data &= ~NSS_IPSECMGR_GENMASK(23, 16);
*data |= (v << 16);
*mask |= NSS_IPSECMGR_GENMASK(23, 16);
break;
case 24: /* bits[24:31] */
*data &= ~NSS_IPSECMGR_GENMASK(31, 24);
*data |= (v << 24);
*mask |= NSS_IPSECMGR_GENMASK(31, 24);
break;
default:
*data = 0;
*mask = 0;
break;
}
}
/*
* nss_ipsecmgr_key_clear_8()
* clear 8-bit mask from the specified position.
*/
static inline void nss_ipsecmgr_key_clear_8(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint32_t *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
mask = &key->mask[idx];
/*
* clear data with mask, update data & save mask
*/
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:7] */
*mask &= ~NSS_IPSECMGR_GENMASK(7, 0);
break;
case 8: /* bits[8:15] */
*mask &= ~NSS_IPSECMGR_GENMASK(15, 8);
break;
case 16: /* bits[16:23] */
*mask &= ~NSS_IPSECMGR_GENMASK(23, 16);
break;
case 24: /* bits[24:31] */
*mask &= ~NSS_IPSECMGR_GENMASK(31, 24);
break;
default:
*mask = 0;
break;
}
}
/*
* nss_ipsecmgr_key_read_16()
* read value & mask from the specified position using mask
*/
static inline uint16_t nss_ipsecmgr_key_read_16(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint32_t data;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
data = key->data[idx];
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:7] */
return (uint16_t)data;
case 16: /* bits[16:23] */
return (uint16_t)(data >> 16);
default:
return 0;
}
}
/*
* nss_ipsecmgr_key_write_16()
* write 16-bit value from the specified position using mask
*/
static inline void nss_ipsecmgr_key_write_16(struct nss_ipsecmgr_key *key, uint16_t v, enum nss_ipsecmgr_key_pos p)
{
uint32_t *data, *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
data = &key->data[idx];
mask = &key->mask[idx];
/*
* clear data with mask, update data & save mask
*/
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:15] */
*data &= ~NSS_IPSECMGR_GENMASK(15, 0);
*data |= v;
*mask |= NSS_IPSECMGR_GENMASK(15, 0);
break;
case 16: /* bits[16:31] */
*data &= ~NSS_IPSECMGR_GENMASK(31, 16);
*data |= (v << 16);
*mask |= NSS_IPSECMGR_GENMASK(31, 16);
break;
default:
*data = 0;
*mask = 0;
break;
}
}
/*
* nss_ipsecmgr_key_clear_16()
* clear 16-bit mask from the specified position
*/
static inline void nss_ipsecmgr_key_clear_16(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint32_t *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
mask = &key->mask[idx];
/*
* clear data with mask, update data & save mask
*/
switch (p % NSS_IPSECMGR_BITS_PER_WORD) {
case 0: /* bits[0:15] */
*mask &= ~NSS_IPSECMGR_GENMASK(15, 0);
break;
case 16: /* bits[16:31] */
*mask &= ~NSS_IPSECMGR_GENMASK(31, 16);
break;
default:
*mask = 0;
break;
}
}
/*
* nss_ipsecmgr_key_read_32()
* read value from the specified position using mask
*/
static inline uint32_t nss_ipsecmgr_key_read_32(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
return key->data[idx];
}
/*
* nss_ipsecmgr_key_write_32()
* write 32-bit value from the specified position using mask
*/
static inline void nss_ipsecmgr_key_write_32(struct nss_ipsecmgr_key *key, uint32_t v, enum nss_ipsecmgr_key_pos p)
{
uint32_t *data, *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
data = &key->data[idx];
mask = &key->mask[idx];
/*
* save data & mask, bits[0:31]
*/
*data = v;
*mask = NSS_IPSECMGR_GENMASK(31, 0);
}
/*
* nss_ipsecmgr_key_clear_32()
* clear 32-bit mask from the specified position
*/
static inline void nss_ipsecmgr_key_clear_32(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
key->mask[idx] = 0;
}
/*
* nss_ipsecmgr_key_clear_64()
* clear 64-bit mask from the specified position
*/
static inline void nss_ipsecmgr_key_clear_64(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
key->mask[idx] = 0;
key->mask[idx + 1] = 0;
}
/*
* nss_ipsecmgr_key_clear_128()
* clear 128-bit mask from the specified position
*/
static inline void nss_ipsecmgr_key_clear_128(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
memset(&key->mask[idx], 0, sizeof(uint32_t) * 4);
}
/*
* nss_ipsecmgr_key_read_n()
* read n nnumber of values from the specified position using mask
*/
static inline void nss_ipsecmgr_key_read(struct nss_ipsecmgr_key *key, uint32_t *v, uint32_t *m, enum nss_ipsecmgr_key_pos p, uint32_t n)
{
uint32_t *k_data, *k_mask;
uint16_t idx;
int delta;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
delta = NSS_IPSECMGR_MAX_KEY_WORDS - idx;
n = n > delta ? delta : n;
k_data = &key->data[idx];
k_mask = &key->mask[idx];
for (; n--;) {
*v++ = *k_data++;
*m++ = *k_mask++;
}
}
/*
* nss_ipsecmgr_key_write()
* write value from the specified position using mask
*/
static inline void nss_ipsecmgr_key_write(struct nss_ipsecmgr_key *key, uint32_t *v, uint32_t *m, enum nss_ipsecmgr_key_pos p, uint32_t n)
{
uint32_t *k_data, *k_mask;
uint16_t idx;
int delta;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
delta = NSS_IPSECMGR_MAX_KEY_WORDS - idx;
n = n > delta ? delta : n;
k_data = &key->data[idx];
k_mask = &key->mask[idx];
for (; n--;) {
*k_data++ = *v++;
*k_mask++ = *m++;
}
}
/*
* nss_ipsecmgr_write_key_mask()
* write a mask starting from position
*/
static inline void nss_ipsecmgr_key_write_mask(struct nss_ipsecmgr_key *key, uint32_t m, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
key->mask[idx] = m;
}
/*
* nss_ipsecmgr_read_key_mask32()
* read a 32 bit mask starting from position
*/
static inline uint32_t nss_ipsecmgr_key_read_mask32(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
return key->mask[idx];
}
/*
* nss_ipsecmgr_read_key_mask64()
* read a 64 bit mask starting from position
*/
static inline uint64_t nss_ipsecmgr_key_read_mask64(struct nss_ipsecmgr_key *key, enum nss_ipsecmgr_key_pos p)
{
uint64_t *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
mask = (uint64_t *)&key->mask[idx];
return *mask;
}
/*
* nss_ipsecmgr_key_lshift_mask()
* left shift mask by an amount 's'
*/
static inline void nss_ipsecmgr_key_lshift_mask(struct nss_ipsecmgr_key *key, uint32_t s, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
key->mask[idx] <<= s;
}
/*
* nss_ipsecmgr_key_lshift_mask64()
* left shift mask by an amount 's'
*/
static inline void nss_ipsecmgr_key_lshift_mask64(struct nss_ipsecmgr_key *key, uint32_t s, enum nss_ipsecmgr_key_pos p)
{
uint64_t *mask;
uint16_t idx;
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
mask = (uint64_t *)&key->mask[idx];
*mask <<= s;
}
/*
* nss_ipsecmgr_key_lshift_mask128()
* left shift mask by an amount 's'
*/
static inline void nss_ipsecmgr_key_lshift_mask128(struct nss_ipsecmgr_key *key, uint32_t s, enum nss_ipsecmgr_key_pos p)
{
uint16_t idx;
uint32_t mask[4];
idx = NSS_IPSECMGR_BITS2WORD(p) % NSS_IPSECMGR_MAX_KEY_WORDS;
memcpy(mask, &key->mask[idx], sizeof(uint32_t) * 4);
bitmap_shift_left((unsigned long *)&key->mask[idx], (unsigned long *)mask, s, 128);
}
/*
* nss_ipsecmgr_key_cmp_data()
* compare source key with destination key
*
* Note: this applies the source mask before comparison
*/
static inline bool nss_ipsecmgr_key_cmp(struct nss_ipsecmgr_key *s_key, struct nss_ipsecmgr_key *d_key)
{
uint32_t *mask = s_key->mask;
uint32_t *src = s_key->data;
uint32_t *dst = d_key->data;
int len = s_key->len;
uint32_t val_0;
uint32_t val_1;
bool status;
for (status = 0; !status && len; len--, mask++, src++, dst++) {
/*
* the data for comparison should be used after
* masking the bits corresponding to that word
*/
val_0 = *src & *mask;
val_1 = *dst & *mask;
status |= val_0 ^ val_1;
}
return status == 0;
}
/*
* nss_ipsecmgr_key_data2idx()
* convert word stream to index based on table size
*/
static inline uint32_t nss_ipsecmgr_key_data2idx(struct nss_ipsecmgr_key *key, const uint32_t table_sz)
{
uint32_t *data = key->data;
uint32_t *mask = key->mask;
uint32_t len = key->len;
uint32_t idx;
uint32_t val;
/*
* bug on if table_sz is not
* - a constant
* - and a power of 2
*/
BUG_ON(!NSS_IPSECMGR_CHK_POW2(table_sz));
for (idx = 0; len; len--, mask++, data++) {
val = *data & *mask;
idx ^= val;
}
return idx & (table_sz - 1);
}
/*
* nss_ipsecmgr_init_sa_db()
* initialize the SA database
*/
static inline void nss_ipsecmgr_init_sa_db(struct nss_ipsecmgr_sa_db *sa_db)
{
struct list_head *head;
int i;
/*
* initialize the SA database
*/
head = sa_db->entries;
for (i = 0; i < NSS_IPSECMGR_MAX_SA; i++, head++) {
INIT_LIST_HEAD(head);
}
atomic_set(&sa_db->num_entries, 0);
}
/*
* nss_ipsecmgr_init_netmask_db()
* initialize the netmask database
*/
static inline void nss_ipsecmgr_init_netmask_db(struct nss_ipsecmgr_netmask_db *net_db)
{
memset(net_db, 0, sizeof(struct nss_ipsecmgr_netmask_db));
atomic_set(&net_db->num_entries, 0);
}
/*
* nss_ipsecmgr_init_subnet_db()
* initialize the subnet database
*/
static inline void nss_ipsecmgr_init_subnet_db(struct nss_ipsecmgr_netmask_entry *netmask)
{
struct list_head *head;
int i;
/*
* initialize the subnet database
*/
head = netmask->subnets;
for (i = 0; i < NSS_IPSECMGR_MAX_SUBNET; i++, head++) {
INIT_LIST_HEAD(head);
}
}
/*
* nss_ipsecmgr_init_flow_db()
* Initialize the flow databases
*/
static inline void nss_ipsecmgr_init_flow_db(struct nss_ipsecmgr_flow_db *flow_db)
{
struct list_head *head;
int i;
/*
* initialize the flow database
*/
head = flow_db->entries;
for (i = 0; i < NSS_IPSECMGR_MAX_FLOW; i++, head++) {
INIT_LIST_HEAD(head);
}
atomic_set(&flow_db->num_entries, 0);
}
/*
* nss_ipsecmgr_init_callback_db()
* initialize the callback database
*/
static inline void nss_ipsecmgr_init_callback_db(struct nss_ipsecmgr_callback_db *cb_db)
{
INIT_LIST_HEAD(&cb_db->entries);
atomic_set(&cb_db->num_entries, 0);
}
/*
* nss_ipsecmgr_v4_hdr2tuple()
* convert v4_hdr to message tuple
*/
static inline void nss_ipsecmgr_v4_hdr2tuple(struct iphdr *iph, struct nss_ipsec_tuple *tuple)
{
tuple->dst_addr[0] = ntohl(iph->daddr);
tuple->src_addr[0] = ntohl(iph->saddr);
tuple->proto_next_hdr = iph->protocol;
tuple->ip_ver = IPVERSION;
}
/*
* nss_ipsecmgr_v6addr_swap()
* Swap the words in the array.
*/
static uint32_t *nss_ipsecmgr_v6addr_swap(uint32_t *src, uint32_t *dst)
{
uint32_t temp[4];
if (src == dst) {
memcpy(temp, src, sizeof(temp));
src = temp;
}
dst[3] = src[0];
dst[2] = src[1];
dst[1] = src[2];
dst[0] = src[3];
return dst;
}
/*
* nss_ipsecmgr_v6addr_ntoh()
* convert the v6 address form network to host order.
*/
static inline uint32_t *nss_ipsecmgr_v6addr_ntoh(uint32_t *src, uint32_t *dst)
{
uint32_t *dst_addr = nss_ipsecmgr_v6addr_swap(src, dst);
dst_addr[0] = ntohl(dst_addr[0]);
dst_addr[1] = ntohl(dst_addr[1]);
dst_addr[2] = ntohl(dst_addr[2]);
dst_addr[3] = ntohl(dst_addr[3]);
return dst_addr;
}
/*
* nss_ipsecmgr_v6addr_hton()
* convert the v6 address to host to network order.
*/
static inline uint32_t *nss_ipsecmgr_v6addr_hton(uint32_t *src, uint32_t *dst)
{
uint32_t *dst_addr = nss_ipsecmgr_v6addr_swap(src, dst);
dst_addr[0] = htonl(dst_addr[0]);
dst_addr[1] = htonl(dst_addr[1]);
dst_addr[2] = htonl(dst_addr[2]);
dst_addr[3] = htonl(dst_addr[3]);
return dst_addr;
}
/*
* nss_ipsecmgr_copy_nim()
* copy nim from source to destination, also swap the v6 addresses if any
*/
static inline void nss_ipsecmgr_copy_nim(struct nss_ipsec_msg *src_nim, struct nss_ipsec_msg *dst_nim)
{
struct nss_ipsec_rule *src_rule = &src_nim->msg.rule;
struct nss_ipsec_rule *dst_rule = &dst_nim->msg.rule;
memcpy(dst_nim, src_nim, sizeof(struct nss_ipsec_msg));
if (src_nim->tuple.ip_ver == 6) {
nss_ipsecmgr_v6addr_swap(src_nim->tuple.dst_addr, dst_nim->tuple.dst_addr);
nss_ipsecmgr_v6addr_swap(src_nim->tuple.src_addr, dst_nim->tuple.src_addr);
}
if (src_rule->oip.ip_ver == 6) {
nss_ipsecmgr_v6addr_swap(src_rule->oip.dst_addr, dst_rule->oip.dst_addr);
nss_ipsecmgr_v6addr_swap(src_rule->oip.src_addr, dst_rule->oip.src_addr);
}
}
/*
* nss_ipsecmgr_v6_hdr2tuple()
* convert v6_hdr to message tuple
*/
static inline void nss_ipsecmgr_v6_hdr2tuple(struct ipv6hdr *iph, struct nss_ipsec_tuple *tuple)
{
uint8_t nexthdr = iph->nexthdr;
struct frag_hdr *frag;
/*
* NSS IPsec module will not accelerate the flows which has ipv6 optional
* headers after frag_hdr. Those flows will be descarded in ipsecmgr.
* The NSS only accelerates when IP next header is L4 or fragment next header is L4.
*/
if (nexthdr == IPPROTO_FRAGMENT) {
frag = (struct frag_hdr *)((uint8_t *)iph + sizeof(struct ipv6hdr));
nexthdr = frag->nexthdr;
}
nss_ipsecmgr_v6addr_ntoh(iph->daddr.s6_addr32, tuple->dst_addr);
nss_ipsecmgr_v6addr_ntoh(iph->saddr.s6_addr32, tuple->src_addr);
tuple->proto_next_hdr = nexthdr;
tuple->ip_ver = 6;
}
/*
* nss_ipsecmgr_get_ipv4_addr()
* Return ipv4 part of the address.
*/
static inline uint32_t nss_ipsecmgr_get_v4addr(uint32_t *addr)
{
return addr[0];
}
/*
* nss_ipsecmgr_verify_v4_subnet()
* verify if v4 subnet mask is not empty when v4 subnet is empty.
*/
static inline bool nss_ipsecmgr_verify_v4_subnet(struct nss_ipsecmgr_encap_v4_subnet *v4_subnet)
{
return !v4_subnet->dst_subnet && v4_subnet->dst_mask;
}
/*
* nss_ipsecmgr_verify_v6_subnet()
* verify if v6 subnet mask is not empty when v6 subnet is empty.
*/
static inline bool nss_ipsecmgr_verify_v6_subnet(struct nss_ipsecmgr_encap_v6_subnet *v6_subnet)
{
bool subnet, mask;
subnet = bitmap_empty((unsigned long *)v6_subnet->dst_subnet, NSS_IPSECMGR_V6_SUBNET_BITS);
mask = bitmap_empty((unsigned long *)v6_subnet->dst_mask, NSS_IPSECMGR_V6_SUBNET_BITS);
return subnet && !mask;
}
/*
* Reference Object API(s)
*/
void nss_ipsecmgr_ref_init(struct nss_ipsecmgr_ref *ref, nss_ipsecmgr_ref_update_t update, nss_ipsecmgr_ref_free_t free);
void nss_ipsecmgr_ref_add(struct nss_ipsecmgr_ref *child, struct nss_ipsecmgr_ref *parent);
void nss_ipsecmgr_ref_free(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_ref *ref);
void nss_ipsecmgr_ref_update(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_ref *ref, struct nss_ipsec_msg *nim);
bool nss_ipsecmgr_ref_is_child(struct nss_ipsecmgr_ref *child, struct nss_ipsecmgr_ref *parent);
void nss_ipsecmgr_ref_set_overhead(struct nss_ipsecmgr_ref *ref,
nss_ipsecmgr_ref_overhead_t overhead);
uint32_t nss_ipsecmgr_ref_overhead(struct nss_ipsecmgr_ref *ref);
/*
* Encap flow API(s)
*/
void nss_ipsecmgr_copy_encap_v4_flow(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_encap_v4_tuple *flow);
void nss_ipsecmgr_copy_encap_v6_flow(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_encap_v6_tuple *flow);
void nss_ipsecmgr_encap_v4_flow2key(struct nss_ipsecmgr_encap_v4_tuple *flow, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_encap_v6_flow2key(struct nss_ipsecmgr_encap_v6_tuple *flow, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_encap_tuple2key(struct nss_ipsec_tuple *tuple, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_encap_flow_init(struct nss_ipsec_msg *nim, enum nss_ipsec_msg_type type, struct nss_ipsecmgr_priv *priv);
/*
* Decap flow API(s)
*/
void nss_ipsecmgr_copy_decap_v4_flow(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_v4 *flow);
void nss_ipsecmgr_copy_decap_v6_flow(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_v6 *flow);
void nss_ipsecmgr_decap_v4_flow2key(struct nss_ipsecmgr_sa_v4 *flow, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_decap_v6_flow2key(struct nss_ipsecmgr_sa_v6 *flow, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_decap_tuple2key(struct nss_ipsec_tuple *tuple, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_decap_flow_init(struct nss_ipsec_msg *nim, enum nss_ipsec_msg_type type, struct nss_ipsecmgr_priv *priv);
/*
* flow alloc/lookup API(s)
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_flow_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
struct nss_ipsecmgr_ref *nss_ipsecmgr_flow_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
bool nss_ipsecmgr_flow_offload(struct nss_ipsecmgr_priv *priv,
struct sk_buff *skb, struct nss_ipsecmgr_flow_data *data);
bool nss_ipsecmgr_flow_process_pmtu(struct nss_ipsecmgr_priv *priv,
struct sk_buff *skb, struct nss_ipsecmgr_flow_data *data);
/*
* Subnet API(s)
*/
void nss_ipsecmgr_copy_subnet(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_ref *subnet_ref);
void nss_ipsecmgr_v4_subnet2key(struct nss_ipsecmgr_encap_v4_subnet *subnet, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_v6_subnet2key(struct nss_ipsecmgr_encap_v6_subnet *subnet, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_v4_subnet_tuple2key(struct nss_ipsec_tuple *tuple, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_v6_subnet_tuple2key(struct nss_ipsec_tuple *tuple, struct nss_ipsecmgr_key *key);
/*
* Subnet alloc/lookup API(s)
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_subnet_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
struct nss_ipsecmgr_ref *nss_ipsecmgr_subnet_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
struct nss_ipsecmgr_ref *nss_ipsecmgr_v4_subnet_match(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *tuple);
struct nss_ipsecmgr_ref *nss_ipsecmgr_v6_subnet_match(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *tuple);
/*
* SA API(s)
*/
void nss_ipsecmgr_copy_v4_sa(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_v4 *sa);
void nss_ipsecmgr_copy_v6_sa(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_v6 *sa);
void nss_ipsecmgr_copy_sa_data(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_data *data);
void nss_ipsecmgr_v4_sa2key(struct nss_ipsecmgr_sa_v4 *sa, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_v6_sa2key(struct nss_ipsecmgr_sa_v6 *sa, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_sa_tuple2key(struct nss_ipsec_tuple *tuple, struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_sa_stats_update(struct nss_ipsec_msg *nim, struct nss_ipsecmgr_sa_entry *sa);
/*
* SA alloc/lookup/flush API(s)
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_lookup(struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_sa_flush_all(struct nss_ipsecmgr_priv *priv);
/*
* Stats op functions.
*/
ssize_t nss_ipsecmgr_netmask_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
ssize_t nss_ipsecmgr_sa_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
ssize_t nss_ipsecmgr_per_flow_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
ssize_t nss_ipsecmgr_per_flow_stats_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos);
ssize_t nss_ipsecmgr_flow_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
#endif /* __NSS_IPSECMGR_PRIV_H */