mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-04 00:00:14 -04:00
Merge branch 'hw-packet-offload'
This adds support for the new "packet" hardware offload feature that's added to the Linux kernel with 6.2. In this mode, the device handles the complete framing of the ESP packet as well as the policy checks, in addition to the crypto. For the IKE sockets, port-based bypass policies are automatically offloaded to devices that support it. Closes strongswan/strongswan#1462
This commit is contained in:
commit
3cf5653640
@ -17,11 +17,8 @@ strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \
|
||||
pkcs1 pkcs8 pem xcbc hmac kdf kernel-netlink socket-default android-dns \
|
||||
stroke eap-identity eap-mschapv2 eap-md5 eap-gtc
|
||||
|
||||
strongswan_STARTER_PLUGINS := kernel-netlink
|
||||
|
||||
# list of all plugins - used to enable them with the function below
|
||||
strongswan_PLUGINS := $(sort $(strongswan_CHARON_PLUGINS) \
|
||||
$(strongswan_STARTER_PLUGINS))
|
||||
strongswan_PLUGINS := $(sort $(strongswan_CHARON_PLUGINS))
|
||||
|
||||
include $(LOCAL_PATH)/Android.common.mk
|
||||
|
||||
|
10
configure.ac
10
configure.ac
@ -1505,7 +1505,6 @@ m4_include(m4/macros/add-plugin.m4)
|
||||
|
||||
# plugin lists for all components
|
||||
charon_plugins=
|
||||
starter_plugins=
|
||||
pool_plugins=
|
||||
attest_plugins=
|
||||
pki_plugins=
|
||||
@ -1593,10 +1592,10 @@ ADD_PLUGIN([load-tester], [c charon])
|
||||
ADD_PLUGIN([kernel-libipsec], [c charon cmd])
|
||||
ADD_PLUGIN([kernel-wfp], [c charon])
|
||||
ADD_PLUGIN([kernel-iph], [c charon])
|
||||
ADD_PLUGIN([kernel-pfkey], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([kernel-pfroute], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([kernel-netlink], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([selinux], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([kernel-pfkey], [c charon nm cmd])
|
||||
ADD_PLUGIN([kernel-pfroute], [c charon nm cmd])
|
||||
ADD_PLUGIN([kernel-netlink], [c charon nm cmd])
|
||||
ADD_PLUGIN([selinux], [c charon nm cmd])
|
||||
ADD_PLUGIN([resolve], [c charon cmd])
|
||||
ADD_PLUGIN([save-keys], [c])
|
||||
ADD_PLUGIN([socket-default], [c charon nm cmd])
|
||||
@ -1666,7 +1665,6 @@ ADD_PLUGIN([unity], [c charon])
|
||||
ADD_PLUGIN([counters], [c charon])
|
||||
|
||||
AC_SUBST(charon_plugins)
|
||||
AC_SUBST(starter_plugins)
|
||||
AC_SUBST(pool_plugins)
|
||||
AC_SUBST(attest_plugins)
|
||||
AC_SUBST(pki_plugins)
|
||||
|
@ -503,6 +503,7 @@ struct xfrm_user_offload {
|
||||
};
|
||||
#define XFRM_OFFLOAD_IPV6 1
|
||||
#define XFRM_OFFLOAD_INBOUND 2
|
||||
#define XFRM_OFFLOAD_PACKET 4
|
||||
|
||||
#ifndef __KERNEL__
|
||||
/* backwards compatibility for userspace */
|
||||
|
@ -95,7 +95,7 @@ struct kernel_ipsec_add_sa_t {
|
||||
uint16_t cpi;
|
||||
/** TRUE to enable UDP encapsulation for NAT traversal */
|
||||
bool encap;
|
||||
/** no (disabled), yes (enabled), auto (enabled if supported) */
|
||||
/** HW offload mode */
|
||||
hw_offload_t hw_offload;
|
||||
/** Mark the SA should apply to packets after processing */
|
||||
mark_t mark;
|
||||
@ -180,6 +180,8 @@ struct kernel_ipsec_manage_policy_t {
|
||||
policy_priority_t prio;
|
||||
/** Manually-set priority (automatic if set to 0) */
|
||||
uint32_t manual_prio;
|
||||
/** HW offload mode */
|
||||
hw_offload_t hw_offload;
|
||||
/** Source address of the SA(s) tied to this policy */
|
||||
host_t *src;
|
||||
/** Destination address of the SA(s) tied to this policy */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2019 Tobias Brunner
|
||||
* Copyright (C) 2006-2023 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2008-2016 Andreas Steffen
|
||||
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
|
||||
@ -108,11 +108,6 @@
|
||||
*/
|
||||
#define XFRM_LIMIT(x) ((x) == 0 ? XFRM_INF : (x))
|
||||
|
||||
/**
|
||||
* Create ORable bitfield of XFRM NL groups
|
||||
*/
|
||||
#define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1))
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first rtattr following the nlmsghdr *nlh and the
|
||||
* 'usual' netlink data x like 'struct xfrm_usersa_info'
|
||||
@ -344,7 +339,7 @@ struct private_kernel_netlink_ipsec_t {
|
||||
/**
|
||||
* Netlink xfrm socket to receive acquire and expire events
|
||||
*/
|
||||
int socket_xfrm_events;
|
||||
netlink_event_socket_t *socket_xfrm_events;
|
||||
|
||||
/**
|
||||
* Whether to install routes along policies
|
||||
@ -363,10 +358,34 @@ struct private_kernel_netlink_ipsec_t {
|
||||
bool policy_update;
|
||||
|
||||
/**
|
||||
* Installed port based IKE bypass policies, as bypass_t
|
||||
* Whether to use port-based policies instead of socket policies for the
|
||||
* IKE sockets/ports
|
||||
*/
|
||||
bool port_bypass;
|
||||
|
||||
/**
|
||||
* Installed port-based IKE bypass policies, as bypass_t
|
||||
*
|
||||
* If they are potentially offloaded, the offload mutex has to be locked
|
||||
* when modifying it
|
||||
*/
|
||||
array_t *bypass;
|
||||
|
||||
/**
|
||||
* Interfaces that potentially support HW offloading, as offload_iface_t
|
||||
*/
|
||||
hashtable_t *offload_interfaces;
|
||||
|
||||
/**
|
||||
* Mutex to safely access the interfaces and bypasses
|
||||
*/
|
||||
mutex_t *offload_mutex;
|
||||
|
||||
/**
|
||||
* Netlink routing socket to receive link events
|
||||
*/
|
||||
netlink_event_socket_t *socket_link_events;
|
||||
|
||||
/**
|
||||
* Custom priority calculation function
|
||||
*/
|
||||
@ -392,6 +411,9 @@ struct ipsec_sa_t {
|
||||
/** Optional mark */
|
||||
uint32_t if_id;
|
||||
|
||||
/** Optional HW offload */
|
||||
hw_offload_t hw_offload;
|
||||
|
||||
/** Description of this SA */
|
||||
ipsec_sa_cfg_t cfg;
|
||||
|
||||
@ -408,7 +430,8 @@ static u_int ipsec_sa_hash(ipsec_sa_t *sa)
|
||||
chunk_hash_inc(sa->dst->get_address(sa->dst),
|
||||
chunk_hash_inc(chunk_from_thing(sa->mark),
|
||||
chunk_hash_inc(chunk_from_thing(sa->if_id),
|
||||
chunk_hash(chunk_from_thing(sa->cfg))))));
|
||||
chunk_hash_inc(chunk_from_thing(sa->hw_offload),
|
||||
chunk_hash(chunk_from_thing(sa->cfg)))))));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -421,6 +444,7 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
|
||||
sa->mark.value == other_sa->mark.value &&
|
||||
sa->mark.mask == other_sa->mark.mask &&
|
||||
sa->if_id == other_sa->if_id &&
|
||||
sa->hw_offload == other_sa->hw_offload &&
|
||||
ipsec_sa_cfg_equals(&sa->cfg, &other_sa->cfg);
|
||||
}
|
||||
|
||||
@ -429,7 +453,8 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
|
||||
*/
|
||||
static ipsec_sa_t *ipsec_sa_create(private_kernel_netlink_ipsec_t *this,
|
||||
host_t *src, host_t *dst, mark_t mark,
|
||||
uint32_t if_id, ipsec_sa_cfg_t *cfg)
|
||||
uint32_t if_id, hw_offload_t hw_offload,
|
||||
ipsec_sa_cfg_t *cfg)
|
||||
{
|
||||
ipsec_sa_t *sa, *found;
|
||||
INIT(sa,
|
||||
@ -437,6 +462,7 @@ static ipsec_sa_t *ipsec_sa_create(private_kernel_netlink_ipsec_t *this,
|
||||
.dst = dst,
|
||||
.mark = mark,
|
||||
.if_id = if_id,
|
||||
.hw_offload = hw_offload,
|
||||
.cfg = *cfg,
|
||||
);
|
||||
found = this->sas->get(this->sas, sa);
|
||||
@ -511,7 +537,7 @@ struct policy_sa_out_t {
|
||||
static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
|
||||
policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst,
|
||||
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, mark_t mark,
|
||||
uint32_t if_id, ipsec_sa_cfg_t *cfg)
|
||||
uint32_t if_id, hw_offload_t hw_offload, ipsec_sa_cfg_t *cfg)
|
||||
{
|
||||
policy_sa_t *policy;
|
||||
|
||||
@ -529,7 +555,7 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
|
||||
INIT(policy, .priority = 0);
|
||||
}
|
||||
policy->type = type;
|
||||
policy->sa = ipsec_sa_create(this, src, dst, mark, if_id, cfg);
|
||||
policy->sa = ipsec_sa_create(this, src, dst, mark, if_id, hw_offload, cfg);
|
||||
return policy;
|
||||
}
|
||||
|
||||
@ -1104,45 +1130,9 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives events from kernel
|
||||
*/
|
||||
static bool receive_events(private_kernel_netlink_ipsec_t *this, int fd,
|
||||
watcher_event_t event)
|
||||
CALLBACK(receive_events, void,
|
||||
private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
|
||||
{
|
||||
char response[netlink_get_buflen()];
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)response;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int len;
|
||||
|
||||
len = recvfrom(this->socket_xfrm_events, response, sizeof(response),
|
||||
MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);
|
||||
if (len < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EINTR:
|
||||
/* interrupted, try again */
|
||||
return TRUE;
|
||||
case EAGAIN:
|
||||
/* no data ready, select again */
|
||||
return TRUE;
|
||||
default:
|
||||
DBG1(DBG_KNL, "unable to receive from XFRM event socket: %s "
|
||||
"(%d)", strerror(errno), errno);
|
||||
sleep(1);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr.nl_pid != 0)
|
||||
{ /* not from kernel. not interested, try another one */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
switch (hdr->nlmsg_type)
|
||||
{
|
||||
case XFRM_MSG_ACQUIRE:
|
||||
@ -1162,9 +1152,6 @@ static bool receive_events(private_kernel_netlink_ipsec_t *this, int fd,
|
||||
"socket: %d", hdr->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
|
||||
@ -1389,7 +1376,7 @@ static struct {
|
||||
/**
|
||||
* Check if kernel supports HW offload and determine feature flag
|
||||
*/
|
||||
static void netlink_find_offload_feature(const char *ifname)
|
||||
static bool netlink_find_offload_feature(const char *ifname)
|
||||
{
|
||||
struct ethtool_sset_info *sset_info;
|
||||
struct ethtool_gstrings *cmd = NULL;
|
||||
@ -1401,7 +1388,7 @@ static void netlink_find_offload_feature(const char *ifname)
|
||||
query_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
|
||||
if (query_socket < 0)
|
||||
{
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* determine number of device features */
|
||||
@ -1453,10 +1440,11 @@ out:
|
||||
free(sset_info);
|
||||
free(cmd);
|
||||
close(query_socket);
|
||||
return netlink_hw_offload.supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if interface supported HW offload
|
||||
* Check if interface supports HW offload
|
||||
*/
|
||||
static bool netlink_detect_offload(const char *ifname)
|
||||
{
|
||||
@ -1497,11 +1485,6 @@ static bool netlink_detect_offload(const char *ifname)
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
DBG1(DBG_KNL, "HW offload is not supported by device");
|
||||
}
|
||||
free(cmd);
|
||||
close(query_socket);
|
||||
return ret;
|
||||
@ -1509,8 +1492,9 @@ static bool netlink_detect_offload(const char *ifname)
|
||||
|
||||
#else
|
||||
|
||||
static void netlink_find_offload_feature(const char *ifname)
|
||||
static bool netlink_find_offload_feature(const char *ifname)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool netlink_detect_offload(const char *ifname)
|
||||
@ -1521,53 +1505,66 @@ static bool netlink_detect_offload(const char *ifname)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* There are 3 HW offload configuration values:
|
||||
* Add a HW offload attribute to the given message, return it if it was added.
|
||||
*
|
||||
* There are 4 HW offload configuration values:
|
||||
* 1. HW_OFFLOAD_NO : Do not configure HW offload.
|
||||
* 2. HW_OFFLOAD_YES : Configure HW offload.
|
||||
* Fail SA addition if offload is not supported.
|
||||
* 3. HW_OFFLOAD_AUTO : Configure HW offload if supported by the kernel
|
||||
* and device.
|
||||
* Do not fail SA addition otherwise.
|
||||
* 2. HW_OFFLOAD_CRYPTO : Configure crypto HW offload.
|
||||
* Fail SA addition if crypto offload is not supported.
|
||||
* 3. HW_OFFLOAD_PACKET : Configure packet HW offload.
|
||||
* Fail SA addition if packet offload is not supported.
|
||||
* 4. HW_OFFLOAD_AUTO : Configure packet HW offload if supported by the kernel
|
||||
* and device. If not, configure crypto HW offload if
|
||||
* supported by the kernel and device.
|
||||
* Do not fail SA addition if offload is not supported.
|
||||
*/
|
||||
static bool config_hw_offload(kernel_ipsec_sa_id_t *id,
|
||||
kernel_ipsec_add_sa_t *data, struct nlmsghdr *hdr,
|
||||
int buflen)
|
||||
static bool add_hw_offload(struct nlmsghdr *hdr, int buflen, host_t *local,
|
||||
char *interface, hw_offload_t hw_offload,
|
||||
struct xfrm_user_offload **offload)
|
||||
{
|
||||
host_t *local = data->inbound ? id->dst : id->src;
|
||||
struct xfrm_user_offload *offload;
|
||||
bool hw_offload_yes, ret = FALSE;
|
||||
char *ifname;
|
||||
bool ret;
|
||||
|
||||
/* do Ipsec configuration without offload */
|
||||
if (data->hw_offload == HW_OFFLOAD_NO)
|
||||
/* do IPsec configuration without offload */
|
||||
if (hw_offload == HW_OFFLOAD_NO)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
hw_offload_yes = (data->hw_offload == HW_OFFLOAD_YES);
|
||||
/* unless offloading is forced, we return TRUE even if we fail */
|
||||
ret = (hw_offload == HW_OFFLOAD_AUTO);
|
||||
|
||||
if (!charon->kernel->get_interface(charon->kernel, local, &ifname))
|
||||
if (!local || local->is_anyaddr(local) ||
|
||||
!charon->kernel->get_interface(charon->kernel, local, &ifname))
|
||||
{
|
||||
return !hw_offload_yes;
|
||||
if (!interface || !interface[0])
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ifname = strdup(interface);
|
||||
}
|
||||
|
||||
/* check if interface supports hw_offload */
|
||||
if (!netlink_detect_offload(ifname))
|
||||
{
|
||||
ret = !hw_offload_yes;
|
||||
DBG1(DBG_KNL, "HW offload is not supported by device %s", ifname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* activate HW offload */
|
||||
offload = netlink_reserve(hdr, buflen,
|
||||
XFRMA_OFFLOAD_DEV, sizeof(*offload));
|
||||
if (!offload)
|
||||
*offload = netlink_reserve(hdr, buflen,
|
||||
XFRMA_OFFLOAD_DEV, sizeof(**offload));
|
||||
if (!(*offload))
|
||||
{
|
||||
ret = !hw_offload_yes;
|
||||
goto out;
|
||||
}
|
||||
offload->ifindex = if_nametoindex(ifname);
|
||||
offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0;
|
||||
(*offload)->ifindex = if_nametoindex(ifname);
|
||||
|
||||
if (hw_offload == HW_OFFLOAD_PACKET ||
|
||||
hw_offload == HW_OFFLOAD_AUTO)
|
||||
{
|
||||
(*offload)->flags |= XFRM_OFFLOAD_PACKET;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
@ -1576,6 +1573,63 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a HW offload attribute to the given SA-related message.
|
||||
*/
|
||||
static bool add_hw_offload_sa(struct nlmsghdr *hdr, int buflen,
|
||||
kernel_ipsec_sa_id_t *id,
|
||||
kernel_ipsec_add_sa_t *data,
|
||||
struct xfrm_user_offload **offload)
|
||||
{
|
||||
host_t *local = data->inbound ? id->dst : id->src;
|
||||
|
||||
if (!add_hw_offload(hdr, buflen, local, NULL, data->hw_offload, offload))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (*offload)
|
||||
{
|
||||
(*offload)->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a HW offload attribuet to the given policy-related message.
|
||||
*/
|
||||
static bool add_hw_offload_policy(struct nlmsghdr *hdr, int buflen,
|
||||
policy_entry_t *policy,
|
||||
policy_sa_t *mapping,
|
||||
struct xfrm_user_offload **offload)
|
||||
{
|
||||
ipsec_sa_t *ipsec = mapping->sa;
|
||||
host_t *local = ipsec->src;
|
||||
char ifname[IFNAMSIZ] = "";
|
||||
|
||||
/* only packet offloading is supported for policies, which we try to use
|
||||
* in automatic mode */
|
||||
if (ipsec->hw_offload != HW_OFFLOAD_PACKET &&
|
||||
ipsec->hw_offload != HW_OFFLOAD_AUTO)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (policy->direction)
|
||||
{
|
||||
case POLICY_FWD:
|
||||
/* FWD policies are not offloaded, they are enforced by the kernel */
|
||||
return TRUE;
|
||||
case POLICY_IN:
|
||||
local = ipsec->dst;
|
||||
break;
|
||||
}
|
||||
if (policy->sel.ifindex)
|
||||
{
|
||||
if_indextoname(policy->sel.ifindex, ifname);
|
||||
}
|
||||
return add_hw_offload(hdr, buflen, local, ifname, ipsec->hw_offload, offload);
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||
private_kernel_netlink_ipsec_t *this, kernel_ipsec_sa_id_t *id,
|
||||
kernel_ipsec_add_sa_t *data)
|
||||
@ -1585,6 +1639,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||
char markstr[32] = "";
|
||||
struct nlmsghdr *hdr;
|
||||
struct xfrm_usersa_info *sa;
|
||||
struct xfrm_user_offload *offload = NULL;
|
||||
uint16_t icv_size = 64, ipcomp = data->ipcomp;
|
||||
ipsec_mode_t mode = data->mode, original_mode = data->mode;
|
||||
traffic_selector_t *first_src_ts, *first_dst_ts;
|
||||
@ -2007,7 +2062,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||
}
|
||||
|
||||
DBG2(DBG_KNL, " HW offload: %N", hw_offload_names, data->hw_offload);
|
||||
if (!config_hw_offload(id, data, hdr, sizeof(request)))
|
||||
if (!add_hw_offload_sa(hdr, sizeof(request), id, data, &offload))
|
||||
{
|
||||
DBG1(DBG_KNL, "failed to configure HW offload");
|
||||
goto failed;
|
||||
@ -2015,6 +2070,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||
}
|
||||
|
||||
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
|
||||
|
||||
if (status != SUCCESS && offload && data->hw_offload == HW_OFFLOAD_AUTO)
|
||||
{
|
||||
DBG1(DBG_KNL, "failed to install SA with %N HW offload, trying with "
|
||||
"%N HW offload", hw_offload_names, HW_OFFLOAD_PACKET,
|
||||
hw_offload_names, HW_OFFLOAD_CRYPTO);
|
||||
offload->flags &= ~XFRM_OFFLOAD_PACKET;
|
||||
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
|
||||
}
|
||||
|
||||
if (status == NOT_FOUND && data->update)
|
||||
{
|
||||
DBG1(DBG_KNL, "allocated SPI not found anymore, try to add SAD entry");
|
||||
@ -2745,6 +2810,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
|
||||
policy_entry_t clone;
|
||||
ipsec_sa_t *ipsec = mapping->sa;
|
||||
struct xfrm_userpolicy_info *policy_info;
|
||||
struct xfrm_user_offload *offload = NULL;
|
||||
struct nlmsghdr *hdr;
|
||||
status_t status;
|
||||
int i;
|
||||
@ -2858,9 +2924,26 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
|
||||
policy_change_done(this, policy);
|
||||
return FAILED;
|
||||
}
|
||||
/* make sure this is the last attribute added to the message */
|
||||
if (!add_hw_offload_policy(hdr, sizeof(request), policy, mapping, &offload))
|
||||
{
|
||||
policy_change_done(this, policy);
|
||||
return FAILED;
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
|
||||
|
||||
if (status != SUCCESS && offload && mapping->sa->hw_offload == HW_OFFLOAD_AUTO)
|
||||
{
|
||||
DBG1(DBG_KNL, "failed to install SA with %N HW offload, trying without "
|
||||
"offload", hw_offload_names, HW_OFFLOAD_PACKET);
|
||||
/* the kernel only allows offloading with packet offload and rejects
|
||||
* the attribute if that flag is not set, so remove it again */
|
||||
hdr->nlmsg_len -= RTA_ALIGN(RTA_LENGTH(sizeof(*offload)));
|
||||
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
|
||||
}
|
||||
|
||||
if (status == ALREADY_DONE && !update)
|
||||
{
|
||||
DBG1(DBG_KNL, "policy already exists, try to update it");
|
||||
@ -2948,7 +3031,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
|
||||
/* cache the assigned IPsec SA */
|
||||
assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
|
||||
data->dst, id->src_ts, id->dst_ts, id->mark,
|
||||
id->if_id, data->sa);
|
||||
id->if_id, data->hw_offload, data->sa);
|
||||
assigned_sa->auto_priority = get_priority(policy, data->prio, id->interface);
|
||||
assigned_sa->priority = this->get_priority ? this->get_priority(id, data)
|
||||
: data->manual_prio;
|
||||
@ -3129,6 +3212,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
|
||||
.dst = data->dst,
|
||||
.mark = id->mark,
|
||||
.if_id = id->if_id,
|
||||
.hw_offload = data->hw_offload,
|
||||
.cfg = *data->sa,
|
||||
};
|
||||
char markstr[32] = "", labelstr[128] = "";
|
||||
@ -3362,6 +3446,44 @@ static bool add_socket_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of interface and its offload support
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/**
|
||||
* Interface index
|
||||
*/
|
||||
int ifindex;
|
||||
|
||||
/**
|
||||
* Name of the interface
|
||||
*/
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
/**
|
||||
* Interface flags
|
||||
*/
|
||||
u_int flags;
|
||||
|
||||
/**
|
||||
* Offload state
|
||||
*/
|
||||
enum {
|
||||
/** Offload support unknown */
|
||||
IFACE_OFFLOAD_UNKNOWN,
|
||||
/** No offload supported */
|
||||
IFACE_OFFLOAD_NONE,
|
||||
/** Interface supports at least crypto offload */
|
||||
IFACE_OFFLOAD_DETECTED,
|
||||
/** Interface supports crypto offload, but no packet and policy offload */
|
||||
IFACE_OFFLOAD_CRYPTO,
|
||||
/** Packet and policy offload supported */
|
||||
IFACE_OFFLOAD_PACKET,
|
||||
} offload;
|
||||
|
||||
} offload_iface_t;
|
||||
|
||||
/**
|
||||
* Port based IKE bypass policy
|
||||
*/
|
||||
@ -3375,13 +3497,16 @@ typedef struct {
|
||||
} bypass_t;
|
||||
|
||||
/**
|
||||
* Add or remove a bypass policy from/to kernel
|
||||
* Add or remove a bypass policy from/to kernel. If an interface is given,
|
||||
* the policy is tried to be offloaded to that interface.
|
||||
*/
|
||||
static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
int type, policy_dir_t dir, bypass_t *bypass)
|
||||
int type, policy_dir_t dir, bypass_t *bypass,
|
||||
char *ifname)
|
||||
{
|
||||
netlink_buf_t request;
|
||||
struct xfrm_selector *sel;
|
||||
struct xfrm_user_offload *offload = NULL;
|
||||
struct nlmsghdr *hdr;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
@ -3407,6 +3532,13 @@ static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
policy->lft.hard_packet_limit = XFRM_INF;
|
||||
|
||||
sel = &policy->sel;
|
||||
|
||||
if (ifname &&
|
||||
!add_hw_offload(hdr, sizeof(request), NULL, ifname,
|
||||
HW_OFFLOAD_PACKET, &offload))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else /* XFRM_MSG_DELPOLICY */
|
||||
{
|
||||
@ -3432,13 +3564,136 @@ static bool manage_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
sel->sport = bypass->port;
|
||||
sel->sport_mask = 0xffff;
|
||||
}
|
||||
if (ifname)
|
||||
{
|
||||
sel->ifindex = if_nametoindex(ifname);
|
||||
}
|
||||
return this->socket_xfrm->send_ack(this->socket_xfrm, hdr) == SUCCESS;
|
||||
}
|
||||
|
||||
CALLBACK(remove_port_bypass, void,
|
||||
bypass_t *bypass, int idx, void *user)
|
||||
{
|
||||
private_kernel_netlink_ipsec_t *this = user;
|
||||
enumerator_t *enumerator;
|
||||
offload_iface_t *iface;
|
||||
|
||||
if (this->port_bypass)
|
||||
{
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass, NULL);
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass, NULL);
|
||||
}
|
||||
if (this->offload_interfaces)
|
||||
{
|
||||
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||
{
|
||||
if (iface->offload == IFACE_OFFLOAD_PACKET &&
|
||||
iface->flags & IFF_UP)
|
||||
{
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass,
|
||||
iface->ifname);
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass,
|
||||
iface->ifname);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bypass socket using a port-based bypass policy
|
||||
* Bypass socket using a port-based bypass policy, optionally offloaded to a
|
||||
* given interface
|
||||
*/
|
||||
static bool add_port_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
bypass_t *bypass, char *ifname)
|
||||
{
|
||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_IN, bypass, ifname))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_OUT, bypass, ifname))
|
||||
{
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass, ifname);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offload the given port-based bypass policy to the given interface if possible.
|
||||
*
|
||||
* offload_mutex is assumed to be locked.
|
||||
*/
|
||||
static bool offload_bypass_iface(private_kernel_netlink_ipsec_t *this,
|
||||
bypass_t *bypass, offload_iface_t *iface)
|
||||
{
|
||||
if ((iface->offload == IFACE_OFFLOAD_DETECTED ||
|
||||
iface->offload == IFACE_OFFLOAD_PACKET))
|
||||
{
|
||||
if (add_port_bypass(this, bypass, iface->ifname))
|
||||
{
|
||||
iface->offload = IFACE_OFFLOAD_PACKET;
|
||||
return TRUE;
|
||||
}
|
||||
else if (iface->offload == IFACE_OFFLOAD_DETECTED)
|
||||
{
|
||||
iface->offload = IFACE_OFFLOAD_CRYPTO;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offload all known port-based bypass policies to the given interface.
|
||||
*
|
||||
* offload_mutex is assumed to be locked.
|
||||
*/
|
||||
static void offload_bypasses(private_kernel_netlink_ipsec_t *this,
|
||||
offload_iface_t *iface)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
bypass_t *bypass;
|
||||
|
||||
enumerator = array_create_enumerator(this->bypass);
|
||||
while (enumerator->enumerate(enumerator, &bypass))
|
||||
{
|
||||
if (!offload_bypass_iface(this, bypass, iface))
|
||||
{ /* could indicate a failure but generally means that the interface
|
||||
* does not support offloading */
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offload a new port-based bypass policy to all known interfaces.
|
||||
*
|
||||
* offload_mutex is assumed to be locked.
|
||||
*/
|
||||
static void offload_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
bypass_t *bypass)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
offload_iface_t *iface;
|
||||
|
||||
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||
{
|
||||
if (iface->flags & IFF_UP)
|
||||
{
|
||||
offload_bypass_iface(this, bypass, iface);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offload a bypass policy on supported hardware if the kernel supports it and
|
||||
* optionally install a port-based bypass policy in software.
|
||||
*/
|
||||
static bool add_and_offload_port_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
int fd, int family)
|
||||
{
|
||||
union {
|
||||
@ -3475,39 +3730,38 @@ static bool add_port_bypass(private_kernel_netlink_ipsec_t *this,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_IN, &bypass))
|
||||
if (this->port_bypass &&
|
||||
!add_port_bypass(this, &bypass, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!manage_bypass(this, XFRM_MSG_NEWPOLICY, POLICY_OUT, &bypass))
|
||||
if (this->offload_interfaces)
|
||||
{
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, &bypass);
|
||||
return FALSE;
|
||||
this->offload_mutex->lock(this->offload_mutex);
|
||||
offload_bypass(this, &bypass);
|
||||
/* store it even if no policy was offloaded because an interface that
|
||||
* supports offloading might get activated later */
|
||||
array_insert_create_value(&this->bypass, sizeof(bypass_t),
|
||||
ARRAY_TAIL, &bypass);
|
||||
this->offload_mutex->unlock(this->offload_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
array_insert_create_value(&this->bypass, sizeof(bypass_t),
|
||||
ARRAY_TAIL, &bypass);
|
||||
}
|
||||
array_insert(this->bypass, ARRAY_TAIL, &bypass);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove installed port based bypass policy
|
||||
*/
|
||||
static void remove_port_bypass(bypass_t *bypass, int idx,
|
||||
private_kernel_netlink_ipsec_t *this)
|
||||
{
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_OUT, bypass);
|
||||
manage_bypass(this, XFRM_MSG_DELPOLICY, POLICY_IN, bypass);
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, bypass_socket, bool,
|
||||
private_kernel_netlink_ipsec_t *this, int fd, int family)
|
||||
{
|
||||
if (lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.kernel-netlink.port_bypass", FALSE, lib->ns))
|
||||
if ((this->offload_interfaces || this->port_bypass) &&
|
||||
!add_and_offload_port_bypass(this, fd, family))
|
||||
{
|
||||
return add_port_bypass(this, fd, family);
|
||||
return FALSE;
|
||||
}
|
||||
return add_socket_bypass(this, fd, family);
|
||||
return this->port_bypass || add_socket_bypass(this, fd, family);
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, enable_udp_decap, bool,
|
||||
@ -3523,30 +3777,161 @@ METHOD(kernel_ipsec_t, enable_udp_decap, bool,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CALLBACK(receive_link_events, void,
|
||||
private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
|
||||
{
|
||||
struct ifinfomsg *msg = NLMSG_DATA(hdr);
|
||||
struct rtattr *rta = IFLA_RTA(msg);
|
||||
size_t rtasize = IFLA_PAYLOAD (hdr);
|
||||
offload_iface_t *iface = NULL;
|
||||
char *name = NULL;
|
||||
|
||||
if (hdr->nlmsg_type != RTM_NEWLINK &&
|
||||
hdr->nlmsg_type != RTM_DELLINK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (RTA_OK(rta, rtasize))
|
||||
{
|
||||
switch (rta->rta_type)
|
||||
{
|
||||
case IFLA_IFNAME:
|
||||
name = RTA_DATA(rta);
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, rtasize);
|
||||
}
|
||||
if (!name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->offload_mutex->lock(this->offload_mutex);
|
||||
if (hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
iface = this->offload_interfaces->get(this->offload_interfaces,
|
||||
(void*)(uintptr_t)msg->ifi_index);
|
||||
if (!iface)
|
||||
{
|
||||
INIT(iface,
|
||||
.ifindex = msg->ifi_index
|
||||
);
|
||||
this->offload_interfaces->put(this->offload_interfaces,
|
||||
(void*)(uintptr_t)msg->ifi_index,
|
||||
iface);
|
||||
}
|
||||
/* update name in case an interface is renamed */
|
||||
strncpy(iface->ifname, name, IFNAMSIZ-1);
|
||||
iface->ifname[IFNAMSIZ-1] = '\0';
|
||||
|
||||
if (iface->offload == IFACE_OFFLOAD_UNKNOWN)
|
||||
{
|
||||
if (netlink_detect_offload(iface->ifname))
|
||||
{
|
||||
iface->offload = IFACE_OFFLOAD_DETECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
iface->offload = IFACE_OFFLOAD_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* if an interface is activated or newly detected, try to offload known
|
||||
* IKE bypass policies. we don't have to do anything if the interface
|
||||
* goes down as the kernel automatically removes the state it has for
|
||||
* offloaded policies */
|
||||
if (!(iface->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
|
||||
{
|
||||
offload_bypasses(this, iface);
|
||||
}
|
||||
iface->flags = msg->ifi_flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
iface = this->offload_interfaces->remove(this->offload_interfaces,
|
||||
(void*)(uintptr_t)msg->ifi_index);
|
||||
free(iface);
|
||||
}
|
||||
this->offload_mutex->unlock(this->offload_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate all interfaces and check if they support offloading
|
||||
*/
|
||||
static bool init_offload_interfaces(private_kernel_netlink_ipsec_t *this)
|
||||
{
|
||||
netlink_buf_t request;
|
||||
netlink_socket_t *socket;
|
||||
struct nlmsghdr *out, *current, *in;
|
||||
struct rtgenmsg *msg;
|
||||
size_t len;
|
||||
|
||||
socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
|
||||
if (!socket)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
in = &request.hdr;
|
||||
in->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
in->nlmsg_type = RTM_GETLINK;
|
||||
in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
|
||||
|
||||
msg = NLMSG_DATA(in);
|
||||
msg->rtgen_family = AF_UNSPEC;
|
||||
|
||||
if (socket->send(socket, in, &out, &len) != SUCCESS)
|
||||
{
|
||||
socket->destroy(socket);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
current = out;
|
||||
while (NLMSG_OK(current, len))
|
||||
{
|
||||
receive_link_events(this, current);
|
||||
current = NLMSG_NEXT(current, len);
|
||||
}
|
||||
free(out);
|
||||
socket->destroy(socket);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, destroy, void,
|
||||
private_kernel_netlink_ipsec_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
policy_entry_t *policy;
|
||||
offload_iface_t *iface;
|
||||
|
||||
array_destroy_function(this->bypass,
|
||||
(array_callback_t)remove_port_bypass, this);
|
||||
if (this->socket_xfrm_events > 0)
|
||||
{
|
||||
lib->watcher->remove(lib->watcher, this->socket_xfrm_events);
|
||||
close(this->socket_xfrm_events);
|
||||
}
|
||||
DESTROY_IF(this->socket_link_events);
|
||||
DESTROY_IF(this->socket_xfrm_events);
|
||||
array_destroy_function(this->bypass, remove_port_bypass, this);
|
||||
DESTROY_IF(this->socket_xfrm);
|
||||
enumerator = this->policies->create_enumerator(this->policies);
|
||||
while (enumerator->enumerate(enumerator, &policy, &policy))
|
||||
while (enumerator->enumerate(enumerator, NULL, &policy))
|
||||
{
|
||||
policy_entry_destroy(this, policy);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->policies->destroy(this->policies);
|
||||
this->sas->destroy(this->sas);
|
||||
if (this->offload_interfaces)
|
||||
{
|
||||
enumerator = this->offload_interfaces->create_enumerator(this->offload_interfaces);
|
||||
while (enumerator->enumerate(enumerator, NULL, &iface))
|
||||
{
|
||||
free(iface);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->offload_interfaces->destroy(this->offload_interfaces);
|
||||
}
|
||||
this->condvar->destroy(this->condvar);
|
||||
this->mutex->destroy(this->mutex);
|
||||
DESTROY_IF(this->offload_mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@ -3658,7 +4043,7 @@ static void setup_spd_hash_thresh(private_kernel_netlink_ipsec_t *this,
|
||||
kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||
{
|
||||
private_kernel_netlink_ipsec_t *this;
|
||||
bool register_for_events = TRUE;
|
||||
uint32_t groups;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
@ -3684,7 +4069,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||
(hashtable_equals_t)policy_equals, 32),
|
||||
.sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
|
||||
(hashtable_equals_t)ipsec_sa_equals, 32),
|
||||
.bypass = array_create(sizeof(bypass_t), 0),
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||
.get_priority = dlsym(RTLD_DEFAULT,
|
||||
@ -3696,13 +4080,10 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||
.proto_port_transport = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.kernel-netlink.set_proto_port_transport_sa",
|
||||
FALSE, lib->ns),
|
||||
.port_bypass = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.kernel-netlink.port_bypass", FALSE, lib->ns),
|
||||
);
|
||||
|
||||
if (streq(lib->ns, "starter"))
|
||||
{ /* starter has no threads, so we do not register for kernel events */
|
||||
register_for_events = FALSE;
|
||||
}
|
||||
|
||||
this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names,
|
||||
lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.kernel-netlink.parallel_xfrm", FALSE, lib->ns));
|
||||
@ -3715,38 +4096,32 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
||||
setup_spd_hash_thresh(this, "ipv4", XFRMA_SPD_IPV4_HTHRESH, 32);
|
||||
setup_spd_hash_thresh(this, "ipv6", XFRMA_SPD_IPV6_HTHRESH, 128);
|
||||
|
||||
if (register_for_events)
|
||||
groups = nl_group(XFRMNLGRP_ACQUIRE) | nl_group(XFRMNLGRP_EXPIRE) |
|
||||
nl_group(XFRMNLGRP_MIGRATE) | nl_group(XFRMNLGRP_MAPPING);
|
||||
this->socket_xfrm_events = netlink_event_socket_create(NETLINK_XFRM, groups,
|
||||
receive_events, this);
|
||||
if (!this->socket_xfrm_events)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
|
||||
/* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */
|
||||
this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
|
||||
if (this->socket_xfrm_events <= 0)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to create XFRM event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) |
|
||||
XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING);
|
||||
if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to bind XFRM event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
lib->watcher->add(lib->watcher, this->socket_xfrm_events, WATCHER_READ,
|
||||
(watcher_cb_t)receive_events, this);
|
||||
}
|
||||
|
||||
netlink_find_offload_feature(lib->settings->get_str(lib->settings,
|
||||
if (netlink_find_offload_feature(lib->settings->get_str(lib->settings,
|
||||
"%s.plugins.kernel-netlink.hw_offload_feature_interface",
|
||||
"lo", lib->ns));
|
||||
|
||||
"lo", lib->ns)))
|
||||
{
|
||||
this->offload_interfaces = hashtable_create(hashtable_hash_ptr,
|
||||
hashtable_equals_ptr, 8);
|
||||
this->offload_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
||||
this->socket_link_events = netlink_event_socket_create(NETLINK_ROUTE,
|
||||
nl_group(RTNLGRP_LINK),
|
||||
receive_link_events, this);
|
||||
if (!this->socket_link_events ||
|
||||
!init_offload_interfaces(this))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
@ -79,9 +79,6 @@
|
||||
#define ROUTING_TABLE_PRIO 0
|
||||
#endif
|
||||
|
||||
/** multicast groups (for groups > 31 setsockopt has to be used) */
|
||||
#define nl_group(group) (1 << (group - 1))
|
||||
|
||||
ENUM(rt_msg_names, RTM_NEWLINK, RTM_GETRULE,
|
||||
"RTM_NEWLINK",
|
||||
"RTM_DELLINK",
|
||||
@ -343,9 +340,9 @@ struct private_kernel_netlink_net_t {
|
||||
netlink_socket_t *socket;
|
||||
|
||||
/**
|
||||
* Netlink rt socket to receive address change events
|
||||
* Netlink rt event socket
|
||||
*/
|
||||
int socket_events;
|
||||
netlink_event_socket_t *socket_events;
|
||||
|
||||
/**
|
||||
* earliest time of the next roam event
|
||||
@ -1451,46 +1448,9 @@ static void process_rule(private_kernel_netlink_net_t *this,
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives events from kernel
|
||||
*/
|
||||
static bool receive_events(private_kernel_netlink_net_t *this, int fd,
|
||||
watcher_event_t event)
|
||||
CALLBACK(receive_events, void,
|
||||
private_kernel_netlink_net_t *this, struct nlmsghdr *hdr)
|
||||
{
|
||||
char response[netlink_get_buflen()];
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)response;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int len;
|
||||
|
||||
len = recvfrom(this->socket_events, response, sizeof(response),
|
||||
MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);
|
||||
if (len < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EINTR:
|
||||
/* interrupted, try again */
|
||||
return TRUE;
|
||||
case EAGAIN:
|
||||
/* no data ready, select again */
|
||||
return TRUE;
|
||||
default:
|
||||
DBG1(DBG_KNL, "unable to receive from RT event socket %s (%d)",
|
||||
strerror(errno), errno);
|
||||
sleep(1);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr.nl_pid != 0)
|
||||
{ /* not from kernel. not interested, try another one */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
/* looks good so far, dispatch netlink message */
|
||||
switch (hdr->nlmsg_type)
|
||||
{
|
||||
case RTM_NEWADDR:
|
||||
@ -1518,9 +1478,6 @@ static bool receive_events(private_kernel_netlink_net_t *this, int fd,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/** enumerator over addresses */
|
||||
@ -3056,11 +3013,7 @@ METHOD(kernel_net_t, destroy, void,
|
||||
manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table,
|
||||
this->routing_table_prio);
|
||||
}
|
||||
if (this->socket_events > 0)
|
||||
{
|
||||
lib->watcher->remove(lib->watcher, this->socket_events);
|
||||
close(this->socket_events);
|
||||
}
|
||||
DESTROY_IF(this->socket_events);
|
||||
enumerator = this->routes->ht.create_enumerator(&this->routes->ht);
|
||||
while (enumerator->enumerate(enumerator, NULL, (void**)&route))
|
||||
{
|
||||
@ -3096,7 +3049,7 @@ kernel_netlink_net_t *kernel_netlink_net_create()
|
||||
{
|
||||
private_kernel_netlink_net_t *this;
|
||||
enumerator_t *enumerator;
|
||||
bool register_for_events = TRUE;
|
||||
uint32_t groups;
|
||||
char *exclude;
|
||||
|
||||
INIT(this,
|
||||
@ -3168,11 +3121,6 @@ kernel_netlink_net_t *kernel_netlink_net_create()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (streq(lib->ns, "starter"))
|
||||
{ /* starter has no threads, so we do not register for kernel events */
|
||||
register_for_events = FALSE;
|
||||
}
|
||||
|
||||
exclude = lib->settings->get_str(lib->settings,
|
||||
"%s.ignore_routing_tables", NULL, lib->ns);
|
||||
if (exclude)
|
||||
@ -3194,47 +3142,27 @@ kernel_netlink_net_t *kernel_netlink_net_create()
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (register_for_events)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
|
||||
/* create and bind RT socket for events (address/interface/route changes) */
|
||||
this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (this->socket_events < 0)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to create RT event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
addr.nl_groups = nl_group(RTNLGRP_IPV4_IFADDR) |
|
||||
groups = nl_group(RTNLGRP_IPV4_IFADDR) |
|
||||
nl_group(RTNLGRP_IPV6_IFADDR) |
|
||||
nl_group(RTNLGRP_LINK);
|
||||
if (this->process_route)
|
||||
{
|
||||
addr.nl_groups |= nl_group(RTNLGRP_IPV4_ROUTE) |
|
||||
groups |= nl_group(RTNLGRP_IPV4_ROUTE) |
|
||||
nl_group(RTNLGRP_IPV6_ROUTE);
|
||||
}
|
||||
if (this->process_rules)
|
||||
{
|
||||
addr.nl_groups |= nl_group(RTNLGRP_IPV4_RULE) |
|
||||
groups |= nl_group(RTNLGRP_IPV4_RULE) |
|
||||
nl_group(RTNLGRP_IPV6_RULE);
|
||||
}
|
||||
if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
|
||||
this->socket_events = netlink_event_socket_create(NETLINK_ROUTE, groups,
|
||||
receive_events, this);
|
||||
if (!this->socket_events)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to bind RT event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ,
|
||||
(watcher_cb_t)receive_events, this);
|
||||
}
|
||||
|
||||
if (init_address_list(this) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get interface list");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2022 Tobias Brunner
|
||||
* Copyright (C) 2008-2023 Tobias Brunner
|
||||
* Copyright (C) 2014 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
@ -58,6 +58,7 @@
|
||||
#endif
|
||||
|
||||
typedef struct private_netlink_socket_t private_netlink_socket_t;
|
||||
typedef struct private_netlink_event_socket_t private_netlink_event_socket_t;
|
||||
|
||||
/**
|
||||
* Private variables and functions of netlink_socket_t class.
|
||||
@ -125,6 +126,37 @@ struct private_netlink_socket_t {
|
||||
bool ignore_retransmit_errors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private data of netlink_event_socket_t class
|
||||
*/
|
||||
struct private_netlink_event_socket_t {
|
||||
|
||||
/**
|
||||
* Public interface
|
||||
*/
|
||||
netlink_event_socket_t public;
|
||||
|
||||
/**
|
||||
* Registered callback
|
||||
*/
|
||||
netlink_event_cb_t cb;
|
||||
|
||||
/**
|
||||
* User data to pass to callback
|
||||
*/
|
||||
void *user;
|
||||
|
||||
/**
|
||||
* Netlink socket
|
||||
*/
|
||||
int socket;
|
||||
|
||||
/**
|
||||
* Buffer size for received Netlink messages
|
||||
*/
|
||||
u_int buflen;
|
||||
};
|
||||
|
||||
/**
|
||||
* #definable hook to simulate request message loss
|
||||
*/
|
||||
@ -700,6 +732,92 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
CALLBACK(watch_event, bool,
|
||||
private_netlink_event_socket_t *this, int fd, watcher_event_t event)
|
||||
{
|
||||
char buf[this->buflen];
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)buf;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int len;
|
||||
|
||||
len = recvfrom(this->socket, buf, sizeof(buf), MSG_DONTWAIT,
|
||||
(struct sockaddr*)&addr, &addr_len);
|
||||
if (len < 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
|
||||
{
|
||||
DBG1(DBG_KNL, "netlink event read error: %s", strerror(errno));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else if (addr.nl_pid != 0)
|
||||
{ /* ignore non-kernel messages */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while (NLMSG_OK(hdr, len))
|
||||
{
|
||||
this->cb(this->user, hdr);
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(netlink_event_socket_t, destroy_event, void,
|
||||
private_netlink_event_socket_t *this)
|
||||
{
|
||||
if (this->socket != -1)
|
||||
{
|
||||
lib->watcher->remove(lib->watcher, this->socket);
|
||||
close(this->socket);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups,
|
||||
netlink_event_cb_t cb, void *user)
|
||||
{
|
||||
private_netlink_event_socket_t *this;
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_groups = groups,
|
||||
};
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.destroy = _destroy_event,
|
||||
},
|
||||
.cb = cb,
|
||||
.user = user,
|
||||
.buflen = netlink_get_buflen(),
|
||||
);
|
||||
|
||||
this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
|
||||
if (this->socket == -1)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to create netlink event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy_event(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to bind netlink event socket: %s (%d)",
|
||||
strerror(errno), errno);
|
||||
destroy_event(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lib->watcher->add(lib->watcher, this->socket, WATCHER_READ, watch_event, this);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2022 Tobias Brunner
|
||||
* Copyright (C) 2008-2023 Tobias Brunner
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
*
|
||||
@ -40,7 +40,16 @@ typedef union {
|
||||
u_char bytes[KERNEL_NETLINK_BUFSIZE];
|
||||
} netlink_buf_t __attribute__((aligned(RTA_ALIGNTO)));
|
||||
|
||||
/**
|
||||
* Callback function for netlink events.
|
||||
*
|
||||
* @param user user data, as passed to constructor
|
||||
* @param hdr received netlink message
|
||||
*/
|
||||
typedef void (*netlink_event_cb_t)(void *user, struct nlmsghdr *hdr);
|
||||
|
||||
typedef struct netlink_socket_t netlink_socket_t;
|
||||
typedef struct netlink_event_socket_t netlink_event_socket_t;
|
||||
|
||||
/**
|
||||
* Wrapper around a netlink socket.
|
||||
@ -80,6 +89,45 @@ struct netlink_socket_t {
|
||||
netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
|
||||
bool parallel);
|
||||
|
||||
/**
|
||||
* Wrapper around a bound netlink event socket.
|
||||
*/
|
||||
struct netlink_event_socket_t {
|
||||
|
||||
/**
|
||||
* Destroy the event socket.
|
||||
*/
|
||||
void (*destroy)(netlink_event_socket_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a netlink_event_socket_t object.
|
||||
*
|
||||
* @param protocol protocol type (e.g. NETLINK_XFRM or NETLINK_ROUTE)
|
||||
* @param groups event groups to bind (use nl_group())
|
||||
* @param cb callback to invoke for each event
|
||||
* @param user user data passed to callback
|
||||
*/
|
||||
netlink_event_socket_t *netlink_event_socket_create(int protocol, uint32_t groups,
|
||||
netlink_event_cb_t cb, void *user);
|
||||
|
||||
/**
|
||||
* Helper to create bitmask for Netlink multicast groups.
|
||||
*
|
||||
* For groups > 31, setsockopt() with NETLINK_ADD_MEMBERSHIP has to be used,
|
||||
* which is currently not supported by the event socket.
|
||||
*/
|
||||
static inline uint32_t nl_group(uint32_t group)
|
||||
{
|
||||
if (group > 31)
|
||||
{
|
||||
DBG1(DBG_KNL, "netlink multicast group %d currently not supported",
|
||||
group);
|
||||
return 0;
|
||||
}
|
||||
return group ? (1 << (group - 1)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an rtattr and adds it to the given netlink message.
|
||||
*
|
||||
|
@ -3303,7 +3303,6 @@ METHOD(kernel_ipsec_t, destroy, void,
|
||||
kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
|
||||
{
|
||||
private_kernel_pfkey_ipsec_t *this;
|
||||
bool register_for_events = TRUE;
|
||||
int rcv_buffer;
|
||||
|
||||
INIT(this,
|
||||
@ -3339,11 +3338,6 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
|
||||
FALSE, lib->ns),
|
||||
);
|
||||
|
||||
if (streq(lib->ns, "starter"))
|
||||
{ /* starter has no threads, so we do not register for kernel events */
|
||||
register_for_events = FALSE;
|
||||
}
|
||||
|
||||
/* create a PF_KEY socket to communicate with the kernel */
|
||||
this->socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
|
||||
if (this->socket <= 0)
|
||||
@ -3353,8 +3347,6 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (register_for_events)
|
||||
{
|
||||
/* create a PF_KEY socket for ACQUIRE & EXPIRE */
|
||||
this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
|
||||
if (this->socket_events <= 0)
|
||||
@ -3387,7 +3379,6 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
|
||||
|
||||
lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ,
|
||||
(watcher_cb_t)receive_events, this);
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
@ -2114,21 +2114,9 @@ kernel_pfroute_net_t *kernel_pfroute_net_create()
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (streq(lib->ns, "starter"))
|
||||
{
|
||||
/* starter has no threads, so we do not register for kernel events */
|
||||
if (shutdown(this->socket, SHUT_RD) != 0)
|
||||
{
|
||||
DBG1(DBG_KNL, "closing read end of PF_ROUTE socket failed: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lib->watcher->add(lib->watcher, this->socket, WATCHER_READ,
|
||||
(watcher_cb_t)receive_events, this);
|
||||
}
|
||||
|
||||
if (init_address_list(this) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_KNL, "unable to get interface list");
|
||||
|
@ -1041,7 +1041,9 @@ CALLBACK(parse_hw_offload, bool,
|
||||
{
|
||||
enum_map_t map[] = {
|
||||
{ "no", HW_OFFLOAD_NO },
|
||||
{ "yes", HW_OFFLOAD_YES },
|
||||
{ "yes", HW_OFFLOAD_CRYPTO },
|
||||
{ "crypto", HW_OFFLOAD_CRYPTO },
|
||||
{ "packet", HW_OFFLOAD_PACKET },
|
||||
{ "auto", HW_OFFLOAD_AUTO },
|
||||
};
|
||||
int d;
|
||||
|
@ -1094,6 +1094,7 @@ static status_t install_policies_inbound(private_child_sa_t *this,
|
||||
.type = type,
|
||||
.prio = priority,
|
||||
.manual_prio = manual_prio,
|
||||
.hw_offload = this->config->get_hw_offload(this->config),
|
||||
.src = other_addr,
|
||||
.dst = my_addr,
|
||||
.sa = my_sa,
|
||||
@ -1131,6 +1132,7 @@ static status_t install_policies_outbound(private_child_sa_t *this,
|
||||
.type = type,
|
||||
.prio = priority,
|
||||
.manual_prio = manual_prio,
|
||||
.hw_offload = this->config->get_hw_offload(this->config),
|
||||
.src = my_addr,
|
||||
.dst = other_addr,
|
||||
.sa = other_sa,
|
||||
@ -1206,6 +1208,7 @@ static void del_policies_inbound(private_child_sa_t *this,
|
||||
.type = type,
|
||||
.prio = priority,
|
||||
.manual_prio = manual_prio,
|
||||
.hw_offload = this->config->get_hw_offload(this->config),
|
||||
.src = other_addr,
|
||||
.dst = my_addr,
|
||||
.sa = my_sa,
|
||||
@ -1242,6 +1245,7 @@ static void del_policies_outbound(private_child_sa_t *this,
|
||||
.type = type,
|
||||
.prio = priority,
|
||||
.manual_prio = manual_prio,
|
||||
.hw_offload = this->config->get_hw_offload(this->config),
|
||||
.src = my_addr,
|
||||
.dst = other_addr,
|
||||
.sa = other_sa,
|
||||
|
@ -95,6 +95,7 @@ static bool install_shunt_policy(child_cfg_t *child)
|
||||
policy_type_t policy_type;
|
||||
policy_priority_t policy_prio;
|
||||
status_t status = SUCCESS;
|
||||
hw_offload_t hw_offload;
|
||||
uint32_t manual_prio;
|
||||
char *interface;
|
||||
bool fwd_out;
|
||||
@ -125,6 +126,7 @@ static bool install_shunt_policy(child_cfg_t *child)
|
||||
hosts->destroy(hosts);
|
||||
|
||||
manual_prio = child->get_manual_prio(child);
|
||||
hw_offload = child->get_hw_offload(child);
|
||||
interface = child->get_interface(child);
|
||||
fwd_out = child->has_option(child, OPT_FWD_OUT_POLICIES);
|
||||
|
||||
@ -157,6 +159,7 @@ static bool install_shunt_policy(child_cfg_t *child)
|
||||
.type = policy_type,
|
||||
.prio = policy_prio,
|
||||
.manual_prio = manual_prio,
|
||||
.hw_offload = hw_offload,
|
||||
.src = host_any,
|
||||
.dst = host_any,
|
||||
.sa = &sa,
|
||||
|
@ -40,7 +40,8 @@ ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH,
|
||||
|
||||
ENUM(hw_offload_names, HW_OFFLOAD_NO, HW_OFFLOAD_AUTO,
|
||||
"no",
|
||||
"yes",
|
||||
"crypto",
|
||||
"packet",
|
||||
"auto",
|
||||
);
|
||||
|
||||
|
@ -125,8 +125,9 @@ extern enum_name_t *ipcomp_transform_names;
|
||||
*/
|
||||
enum hw_offload_t {
|
||||
HW_OFFLOAD_NO = 0,
|
||||
HW_OFFLOAD_YES = 1,
|
||||
HW_OFFLOAD_AUTO = 2,
|
||||
HW_OFFLOAD_CRYPTO = 1,
|
||||
HW_OFFLOAD_PACKET = 2,
|
||||
HW_OFFLOAD_AUTO = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -18,8 +18,7 @@ LOCAL_C_INCLUDES += \
|
||||
$(strongswan_PATH)/src/stroke
|
||||
|
||||
LOCAL_CFLAGS := $(strongswan_CFLAGS) \
|
||||
-DIPSEC_SCRIPT='"ipsec"' \
|
||||
-DPLUGINS='"$(strongswan_STARTER_PLUGINS)"'
|
||||
-DIPSEC_SCRIPT='"ipsec"'
|
||||
|
||||
LOCAL_MODULE := starter
|
||||
|
||||
|
@ -24,7 +24,6 @@ AM_CPPFLAGS = \
|
||||
-DIPSEC_SCRIPT=\"${ipsec_script}\" \
|
||||
-DDEV_RANDOM=\"${random_device}\" \
|
||||
-DDEV_URANDOM=\"${urandom_device}\" \
|
||||
-DPLUGINS=\""${starter_plugins}\"" \
|
||||
-DDEBUG
|
||||
|
||||
AM_CFLAGS = \
|
||||
|
@ -1071,10 +1071,12 @@ connections.<conn>.children.<child>.hw_offload = no
|
||||
implementation.
|
||||
|
||||
Enable hardware offload for this CHILD_SA, if supported by the IPsec
|
||||
implementation. The value _yes_ enforces offloading and the installation
|
||||
will fail if it's not supported by either kernel or device. The value _auto_
|
||||
enables offloading, if it's supported, but the installation does not fail
|
||||
otherwise.
|
||||
implementation. The values _crypto_ or _packet_ enforce crypto or full
|
||||
packet offloading and the installation will fail if the selected mode is not
|
||||
supported by either kernel or device. On Linux, _packet_ also offloads
|
||||
policies, including trap policies. The value _auto_ enables full packet
|
||||
or crypto offloading, if either is supported, but the installation does not
|
||||
fail otherwise.
|
||||
|
||||
connections.<conn>.children.<child>.copy_df = yes
|
||||
Whether to copy the DF bit to the outer IPv4 header in tunnel mode.
|
||||
|
Loading…
x
Reference in New Issue
Block a user