blob: f99333682ddd016ca10758b681b718b2bed461d5 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2014-2016, 2020 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.
**************************************************************************
*/
#include <nss_api_if.h>
extern int ecm_nss_ipv4_no_action_limit_default; /* Default no-action limit. */
extern int ecm_nss_ipv4_driver_fail_limit_default; /* Default driver fail limit. */
extern int ecm_nss_ipv4_nack_limit_default; /* Default nack limit. */
extern int ecm_nss_ipv4_accelerated_count; /* Total offloads */
extern int ecm_nss_ipv4_pending_accel_count; /* Total pending offloads issued to the NSS / awaiting completion */
extern int ecm_nss_ipv4_pending_decel_count; /* Total pending deceleration requests issued to the NSS / awaiting completion */
/*
* Limiting the acceleration of connections.
*
* By default there is no acceleration limiting.
* This means that when ECM has more connections (that can be accelerated) than the acceleration
* engine will allow the ECM will continue to try to accelerate.
* In this scenario the acceleration engine will begin removal of existing rules to make way for new ones.
* When the accel_limit_mode is set to FIXED ECM will not permit more rules to be issued than the engine will allow.
*/
extern uint32_t ecm_nss_ipv4_accel_limit_mode;
/*
* Flag to enable/disable bridge VLAN passthrough feature.
* By default this feature is disabled.
*/
extern int ecm_nss_ipv4_vlan_passthrough_enable;
/*
* Locking of the classifier - concurrency control for file global parameters.
* NOTE: It is safe to take this lock WHILE HOLDING a feci->lock. The reverse is NOT SAFE.
*/
extern spinlock_t ecm_nss_ipv4_lock; /* Protect against SMP access between netfilter, events and private threaded function. */
/*
* NSS driver linkage
*/
extern struct nss_ctx_instance *ecm_nss_ipv4_nss_ipv4_mgr;
/*
* ecm_nss_ipv4_accel_pending_set()
* Set pending acceleration for the connection object.
*
* Return false if the acceleration is not permitted or is already in progress.
*/
static inline bool ecm_nss_ipv4_accel_pending_set(struct ecm_front_end_connection_instance *feci)
{
DEBUG_INFO("%px: Accel conn: %px\n", feci, feci->ci);
/*
* If re-generation is required then we cannot permit acceleration
*/
if (ecm_db_connection_regeneration_required_peek(feci->ci)) {
DEBUG_TRACE("%px: accel %px failed - regen required\n", feci, feci->ci);
return false;
}
/*
* Is connection acceleration permanently failed?
*/
spin_lock_bh(&feci->lock);
if (ECM_FRONT_END_ACCELERATION_FAILED(feci->accel_mode)) {
spin_unlock_bh(&feci->lock);
DEBUG_TRACE("%px: accel %px failed\n", feci, feci->ci);
return false;
}
/*
* If acceleration mode is anything other than "not accelerated" then ignore.
*/
if (feci->accel_mode != ECM_FRONT_END_ACCELERATION_MODE_DECEL) {
spin_unlock_bh(&feci->lock);
DEBUG_TRACE("%px: Ignoring wrong mode accel for conn: %px\n", feci, feci->ci);
return false;
}
/*
* Do we have a fixed upper limit for acceleration?
*/
spin_lock_bh(&ecm_nss_ipv4_lock);
if (ecm_nss_ipv4_accel_limit_mode & ECM_FRONT_END_ACCEL_LIMIT_MODE_FIXED) {
if ((ecm_nss_ipv4_pending_accel_count + ecm_nss_ipv4_accelerated_count) >= nss_ipv4_max_conn_count()) {
spin_unlock_bh(&ecm_nss_ipv4_lock);
spin_unlock_bh(&feci->lock);
DEBUG_INFO("%px: Accel limit reached, accel denied: %px\n", feci, feci->ci);
return false;
}
}
/*
* Okay to accelerate
*/
ecm_nss_ipv4_pending_accel_count++;
spin_unlock_bh(&ecm_nss_ipv4_lock);
/*
* Okay connection can be set to pending acceleration
*/
feci->accel_mode = ECM_FRONT_END_ACCELERATION_MODE_ACCEL_PENDING;
spin_unlock_bh(&feci->lock);
return true;
}
/*
* _ecm_nss_ipv4_accel_pending_clear()
* Clear pending acceleration for the connection object, setting it to the desired state.
*
* Returns true if "decelerate was pending".
*
* The feci->lock AND ecm_nss_ipv4_lock must be held on entry.
*/
static inline bool _ecm_nss_ipv4_accel_pending_clear(struct ecm_front_end_connection_instance *feci, ecm_front_end_acceleration_mode_t mode)
{
bool decel_pending;
/*
* Set the mode away from its accel pending state.
*/
DEBUG_ASSERT(feci->accel_mode == ECM_FRONT_END_ACCELERATION_MODE_ACCEL_PENDING, "%px: Accel mode unexpected: %d\n", feci, feci->accel_mode);
feci->accel_mode = mode;
/*
* Clear decelerate pending flag.
* This flag is only set when we are ACCEL_PENDING -
* and we are moving from that to the given mode anyway.
*/
decel_pending = feci->stats.decelerate_pending;
feci->stats.decelerate_pending = false;
/*
* Decrement pending counter
*/
ecm_nss_ipv4_pending_accel_count--;
DEBUG_ASSERT(ecm_nss_ipv4_pending_accel_count >= 0, "Accel pending underflow\n");
return decel_pending;
}
/*
* ecm_nss_ipv4_accel_pending_clear()
* Clear pending acceleration for the connection object, setting it to the desired state.
*/
static inline bool ecm_nss_ipv4_accel_pending_clear(struct ecm_front_end_connection_instance *feci, ecm_front_end_acceleration_mode_t mode)
{
bool decel_pending;
spin_lock_bh(&feci->lock);
spin_lock_bh(&ecm_nss_ipv4_lock);
decel_pending = _ecm_nss_ipv4_accel_pending_clear(feci, mode);
spin_unlock_bh(&ecm_nss_ipv4_lock);
spin_unlock_bh(&feci->lock);
return decel_pending;
}
extern void ecm_nss_ipv4_accel_done_time_update(struct ecm_front_end_connection_instance *feci);
extern void ecm_nss_ipv4_decel_done_time_update(struct ecm_front_end_connection_instance *feci);
extern int ecm_nss_ipv4_init(struct dentry *dentry);
extern void ecm_nss_ipv4_exit(void);