blob: f60b17cc446469d5606e8f829e71a29f334dc65b [file] [log] [blame]
/*
* ********************************************************************************
* Copyright (c) 2016-2019, 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_FLOW_H
#define __NSS_IPSECMGR_FLOW_H
#define NSS_IPSECMGR_FLOW_MAX 1024 /* Maximum number of flow(s) */
#if (~(NSS_IPSECMGR_FLOW_MAX - 1) & (NSS_IPSECMGR_FLOW_MAX >> 1))
#error "NSS_IPSECMGR_FLOW_MAX is not a power of 2"
#endif
#define NSS_IPSECMGR_FLOW_PRINT_EXTRA 64
#define NSS_IPSECMGR_FLOW_FREE_TIMEOUT msecs_to_jiffies(20) /* msecs */
struct nss_ipsecmgr_sa;
/*
* Per flow state
*/
struct nss_ipsecmgr_flow_state {
struct nss_ipsec_cmn_flow_tuple tuple; /* Flow tuple */
struct nss_ipsec_cmn_sa_tuple sa; /* SA tuple; used during deletion */
};
/*
* IPsec manager flow entry
*/
struct nss_ipsecmgr_flow {
struct list_head list; /* List object. */
struct nss_ipsecmgr_ref ref; /* Reference object. */
struct nss_ipsecmgr_sa *sa; /* Parent SA object */
uint32_t ifnum; /* NSS interface attached to flow */
struct nss_ctx_instance *nss_ctx; /* NSS context */
struct nss_ipsecmgr_flow_state state;
int tunnel_id; /* Linux device index */
};
/*
* nss_ipsecmgr_flow_ntoh_v6addr()
* Network to host order and swap
*/
static inline void nss_ipsecmgr_flow_ntoh_v6addr(uint32_t *dest, uint32_t *src)
{
dest[0] = ntohl(src[0]);
dest[1] = ntohl(src[1]);
dest[2] = ntohl(src[2]);
dest[3] = ntohl(src[3]);
}
/*
* nss_ipsecmgr_flow_tuple_match()
* Match flow tuple
*/
static inline bool nss_ipsecmgr_flow_tuple_match(struct nss_ipsec_cmn_flow_tuple *d, struct nss_ipsec_cmn_flow_tuple *s)
{
uint32_t status = 0;
switch (d->ip_ver) {
case IPVERSION:
status += d->dest_ip[0] ^ s->dest_ip[0];
status += d->src_ip[0] ^ s->src_ip[0];
status += d->spi_index ^ s->spi_index;
status += d->protocol ^ s->protocol;
status += d->ip_ver ^ s->ip_ver;
status += d->user_pattern ^ s->user_pattern;
return !status;
default:
status += d->dest_ip[0] ^ s->dest_ip[0];
status += d->dest_ip[1] ^ s->dest_ip[1];
status += d->dest_ip[2] ^ s->dest_ip[2];
status += d->dest_ip[3] ^ s->dest_ip[3];
status += d->src_ip[0] ^ s->src_ip[0];
status += d->src_ip[1] ^ s->src_ip[1];
status += d->src_ip[2] ^ s->src_ip[2];
status += d->src_ip[3] ^ s->src_ip[3];
status += d->spi_index ^ s->spi_index;
status += d->protocol ^ s->protocol;
status += d->ip_ver ^ s->ip_ver;
status += d->user_pattern ^ s->user_pattern;
return !status;
}
}
/*
* nss_ipsecmgr_flow_tuple2index()
* Change tuple to hash index
*/
static inline uint32_t nss_ipsecmgr_flow_tuple2hash(struct nss_ipsec_cmn_flow_tuple *tuple, uint32_t max)
{
uint32_t val = 0;
val ^= tuple->dest_ip[0];
val ^= tuple->src_ip[0];
val ^= tuple->dest_ip[1];
val ^= tuple->src_ip[1];
val ^= tuple->dest_ip[2];
val ^= tuple->src_ip[2];
val ^= tuple->dest_ip[3];
val ^= tuple->src_ip[3];
val ^= tuple->spi_index;
val ^= tuple->protocol;
val ^= tuple->ip_ver;
val ^= tuple->user_pattern;
return val & (max - 1);
}
/*
* nss_ipsecmgr_flow2tuple()
* Change flow to tuple
*/
static inline void nss_ipsecmgr_flow2tuple(struct nss_ipsecmgr_flow_tuple *f, struct nss_ipsec_cmn_flow_tuple *t)
{
memcpy(t->dest_ip, f->dest_ip, sizeof(t->dest_ip));
memcpy(t->src_ip, f->src_ip, sizeof(t->src_ip));
t->spi_index = f->spi_index;
t->protocol = f->proto_next_hdr;
t->ip_ver = f->ip_version;
t->src_port = f->sport;
t->dst_port = f->dport;
t->user_pattern = f->use_pattern;
}
/*
* nss_ipsecmgr_flow_ipv4_inner2tuple()
* Change inner IPv4 flow to tuple
*/
static inline void nss_ipsecmgr_flow_ipv4_inner2tuple(struct iphdr *iph, struct nss_ipsec_cmn_flow_tuple *t)
{
t->src_ip[0] = ntohl(iph->saddr);
t->dest_ip[0] = ntohl(iph->daddr);
t->ip_ver = IPVERSION;
t->protocol = iph->protocol;
}
/*
* nss_ipsecmgr_flow_ipv4_outer2tuple()
* Change outer IPv4 flow to tuple
*/
static inline void nss_ipsecmgr_flow_ipv4_outer2tuple(struct iphdr *iph, struct nss_ipsec_cmn_flow_tuple *t)
{
uint8_t *data = (uint8_t *)iph;
struct ip_esp_hdr *esph;
WARN_ON((iph->protocol != IPPROTO_ESP) && (iph->protocol != IPPROTO_UDP));
t->src_ip[0] = ntohl(iph->saddr);
t->dest_ip[0] = ntohl(iph->daddr);
t->ip_ver = IPVERSION;
t->protocol = iph->protocol;
data += sizeof(*iph);
if (t->protocol == IPPROTO_UDP)
data += sizeof(struct udphdr);
esph = (struct ip_esp_hdr *)data;
t->spi_index = ntohl(esph->spi);
}
/*
* nss_ipsecmgr_flow_ipv6_inner2tuple()
* Change inner IPv6 flow to tuple
*/
static inline void nss_ipsecmgr_flow_ipv6_inner2tuple(struct ipv6hdr *ip6h, struct nss_ipsec_cmn_flow_tuple *t)
{
uint8_t *data = (uint8_t *)ip6h;
struct frag_hdr *fragh;
nss_ipsecmgr_flow_ntoh_v6addr(t->src_ip, ip6h->saddr.s6_addr32);
nss_ipsecmgr_flow_ntoh_v6addr(t->dest_ip, ip6h->daddr.s6_addr32);
t->protocol = ip6h->nexthdr;
t->ip_ver = 6;
data += sizeof(*ip6h);
if (t->protocol == NEXTHDR_FRAGMENT) {
fragh = (struct frag_hdr *)data;
t->protocol = fragh->nexthdr;
}
}
/*
* nss_ipsecmgr_flow_ipv6_outer2tuple()
* Change inner IPv6 flow to tuple
*/
static inline void nss_ipsecmgr_flow_ipv6_outer2tuple(struct ipv6hdr *ip6h, struct nss_ipsec_cmn_flow_tuple *t)
{
uint8_t *data = (uint8_t *)ip6h;
struct ip_esp_hdr *esph;
nss_ipsecmgr_flow_ntoh_v6addr(t->src_ip, ip6h->saddr.s6_addr32);
nss_ipsecmgr_flow_ntoh_v6addr(t->dest_ip, ip6h->daddr.s6_addr32);
t->protocol = ip6h->nexthdr;
t->ip_ver = 6;
WARN_ON(ip6h->nexthdr != IPPROTO_ESP);
data += sizeof(*ip6h);
esph = (struct ip_esp_hdr *)data;
t->spi_index = ntohl(esph->spi);
}
struct nss_ipsecmgr_flow *nss_ipsecmgr_flow_find(struct list_head *db, struct nss_ipsec_cmn_flow_tuple *t);
#endif