blob: ac6b5e7fa6f949df7c5f8b865491897b7e20cd09 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2016, 2018-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 <linux/version.h>
#include <linux/types.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/inet.h>
#include <linux/etherdevice.h>
/*
* Debug output levels
* 0 = OFF
* 1 = ASSERTS / ERRORS
* 2 = 1 + WARN
* 3 = 2 + INFO
* 4 = 3 + TRACE
*/
#define DEBUG_LEVEL ECM_CLASSIFIER_DEBUG_LEVEL
#include "ecm_types.h"
#include "ecm_db_types.h"
#include "ecm_state.h"
#include "ecm_tracker.h"
#include "ecm_front_end_types.h"
#include "ecm_classifier.h"
#include "ecm_db.h"
#ifdef ECM_CLASSIFIER_NL_ENABLE
#include "ecm_classifier_nl.h"
#endif
#ifdef ECM_CLASSIFIER_HYFI_ENABLE
#include "ecm_classifier_hyfi.h"
#endif
#ifdef ECM_CLASSIFIER_DSCP_ENABLE
#include "ecm_classifier_dscp.h"
#endif
#ifdef ECM_CLASSIFIER_PCC_ENABLE
#include "ecm_classifier_pcc.h"
#endif
#ifdef ECM_CLASSIFIER_MARK_ENABLE
#include "ecm_classifier_mark.h"
#endif
#ifdef ECM_CLASSIFIER_OVS_ENABLE
#include "ecm_classifier_ovs.h"
#endif
#ifdef ECM_CLASSIFIER_EMESH_ENABLE
#include "ecm_classifier_emesh.h"
#endif
#ifdef ECM_CLASSIFIER_MSCS_ENABLE
#include "ecm_classifier_mscs.h"
#endif
/*
* Default slow path packets allowed before the acceleration
* 0 - The feature is disabled. Acceleration starts immediately.
* 1 - Acceleration will not start until both direction traffic is seen.
* N - Acceleration will not start until N packets are seen in the slow path.
*/
int ecm_classifier_accel_delay_pkts = 0;
/*
* ecm_classifier_assign_classifier()
* Instantiate and assign classifier of type upon the connection, also returning it if it could be allocated.
*/
struct ecm_classifier_instance *ecm_classifier_assign_classifier(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
{
DEBUG_TRACE("%px: Assign classifier of type: %d\n", ci, type);
DEBUG_ASSERT(type != ECM_CLASSIFIER_TYPE_DEFAULT, "Must never need to instantiate default type in this way");
switch (type) {
#ifdef ECM_CLASSIFIER_PCC_ENABLE
case ECM_CLASSIFIER_TYPE_PCC: {
struct ecm_classifier_pcc_instance *pcci;
pcci = ecm_classifier_pcc_instance_alloc(ci);
if (!pcci) {
DEBUG_TRACE("%px: Failed to create Parental Controls classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created Parental Controls classifier: %px\n", ci, pcci);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)pcci);
return (struct ecm_classifier_instance *)pcci;
}
#endif
#ifdef ECM_CLASSIFIER_OVS_ENABLE
case ECM_CLASSIFIER_TYPE_OVS: {
struct ecm_classifier_ovs_instance *ecvi;
ecvi = ecm_classifier_ovs_instance_alloc(ci);
if (!ecvi) {
DEBUG_TRACE("%px: Failed to create ovs classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created ovs classifier: %px\n", ci, ecvi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)ecvi);
return (struct ecm_classifier_instance *)ecvi;
}
#endif
#ifdef ECM_CLASSIFIER_NL_ENABLE
case ECM_CLASSIFIER_TYPE_NL: {
struct ecm_classifier_nl_instance *cnli;
cnli = ecm_classifier_nl_instance_alloc(ci);
if (!cnli) {
DEBUG_TRACE("%px: Failed to create Netlink classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created Netlink classifier: %px\n", ci, cnli);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)cnli);
return (struct ecm_classifier_instance *)cnli;
}
#endif
#ifdef ECM_CLASSIFIER_EMESH_ENABLE
case ECM_CLASSIFIER_TYPE_EMESH: {
struct ecm_classifier_emesh_instance *cemi;
cemi = ecm_classifier_emesh_instance_alloc(ci);
if (!cemi) {
DEBUG_TRACE("%px: Failed to create emesh classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created emesh classifier: %px\n", ci, cemi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)cemi);
return (struct ecm_classifier_instance *)cemi;
}
#endif
#ifdef ECM_CLASSIFIER_DSCP_ENABLE
case ECM_CLASSIFIER_TYPE_DSCP: {
struct ecm_classifier_dscp_instance *cdscpi;
cdscpi = ecm_classifier_dscp_instance_alloc(ci);
if (!cdscpi) {
DEBUG_TRACE("%px: Failed to create DSCP classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created DSCP classifier: %px\n", ci, cdscpi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)cdscpi);
return (struct ecm_classifier_instance *)cdscpi;
}
#endif
#ifdef ECM_CLASSIFIER_HYFI_ENABLE
case ECM_CLASSIFIER_TYPE_HYFI: {
struct ecm_classifier_hyfi_instance *chfi;
chfi = ecm_classifier_hyfi_instance_alloc(ci);
if (!chfi) {
DEBUG_TRACE("%px: Failed to create HyFi classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created HyFi classifier: %px\n", ci, chfi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)chfi);
return (struct ecm_classifier_instance *)chfi;
}
#endif
#ifdef ECM_CLASSIFIER_MARK_ENABLE
case ECM_CLASSIFIER_TYPE_MARK: {
struct ecm_classifier_mark_instance *ecmi;
ecmi = ecm_classifier_mark_instance_alloc(ci);
if (!ecmi) {
DEBUG_TRACE("%px: Failed to create mark classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created mark classifier: %px\n", ci, ecmi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)ecmi);
return (struct ecm_classifier_instance *)ecmi;
}
#endif
#ifdef ECM_CLASSIFIER_MSCS_ENABLE
case ECM_CLASSIFIER_TYPE_MSCS: {
struct ecm_classifier_mscs_instance *ecmi;
ecmi = ecm_classifier_mscs_instance_alloc(ci);
if (!ecmi) {
DEBUG_TRACE("%px: Failed to create mscs classifier\n", ci);
return NULL;
}
DEBUG_TRACE("%px: Created mscs classifier: %px\n", ci, ecmi);
ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)ecmi);
return (struct ecm_classifier_instance *)ecmi;
}
#endif
default:
DEBUG_ASSERT(NULL, "%px: Unsupported type: %d\n", ci, type);
return NULL;
}
}
/*
* ecm_classifier_reclassify()
* Signal reclassify upon the assigned classifiers.
*
* Classifiers that unassigned themselves we TRY to re-instantiate them.
* Returns false if the function is not able to instantiate all missing classifiers.
* This function does not release and references to classifiers in the assignments[].
*/
bool ecm_classifier_reclassify(struct ecm_db_connection_instance *ci, int assignment_count, struct ecm_classifier_instance *assignments[])
{
ecm_classifier_type_t classifier_type;
int i;
bool full_reclassification = true;
/*
* assignment_count will always be <= the number of classifier types available
*/
for (i = 0, classifier_type = ECM_CLASSIFIER_TYPE_DEFAULT; i < assignment_count; ++i, ++classifier_type) {
ecm_classifier_type_t aci_type;
struct ecm_classifier_instance *aci;
aci = assignments[i];
aci_type = aci->type_get(aci);
DEBUG_TRACE("%px: Reclassify: %d\n", ci, aci_type);
aci->reclassify(aci);
/*
* If the connection has a full complement of assigned classifiers then these will match 1:1 with the classifier_type (all in same order).
* If not, we have to create the missing ones.
*/
if (aci_type == classifier_type) {
continue;
}
/*
* Need to instantiate the missing classifier types until we get to the same type as aci_type then we are back in sync to continue reclassification
*/
while (classifier_type != aci_type) {
struct ecm_classifier_instance *naci;
DEBUG_TRACE("%px: Instantiate missing type: %d\n", ci, classifier_type);
DEBUG_ASSERT(classifier_type < ECM_CLASSIFIER_TYPES, "Algorithm bad");
naci = ecm_classifier_assign_classifier(ci, classifier_type);
if (!naci) {
full_reclassification = false;
} else {
naci->deref(naci);
}
classifier_type++;
}
}
/*
* Add missing types
*/
for (; classifier_type < ECM_CLASSIFIER_TYPES; ++classifier_type) {
struct ecm_classifier_instance *naci;
DEBUG_TRACE("%px: Instantiate missing type: %d\n", ci, classifier_type);
naci = ecm_classifier_assign_classifier(ci, classifier_type);
if (!naci) {
full_reclassification = false;
} else {
naci->deref(naci);
}
}
DEBUG_TRACE("%px: reclassify done: %u\n", ci, full_reclassification);
return full_reclassification;
}