[qca-nss-ecm] Add Mark Classifier
With this classifier an external kernel module which
is registered with this classifiers callbacks can inspect
the skb and make smart decisions on that buffer, returns
a mark value extracted from the buffer for future use.
Change-Id: I6b1cce6585d105603bef84f697bc0d47fb6b0105
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
diff --git a/Makefile b/Makefile
index cd25069..34f48d4 100755
--- a/Makefile
+++ b/Makefile
@@ -196,6 +196,13 @@
ccflags-$(ECM_IPV6_ENABLE) += -DECM_IPV6_ENABLE
# #############################################################################
+# Define ECM_CLASSIFIER_MARK_ENABLE=y in order to enable mark classifier.
+# #############################################################################
+ECM_CLASSIFIER_MARK_ENABLE=y
+ecm-$(ECM_CLASSIFIER_MARK_ENABLE) += ecm_classifier_mark.o
+ccflags-$(ECM_CLASSIFIER_MARK_ENABLE) += -DECM_CLASSIFIER_MARK_ENABLE
+
+# #############################################################################
# Define ECM_CLASSIFIER_NL_ENABLE=y in order to enable NL classifier.
# #############################################################################
ifeq ($(findstring 4.4., $(KERNELVERSION)),)
@@ -299,6 +306,7 @@
# By turning off debugs you gain maximum ECM performance.
# #############################################################################
ccflags-y += -DECM_CLASSIFIER_DEBUG_LEVEL=1
+ccflags-y += -DECM_CLASSIFIER_MARK_DEBUG_LEVEL=1
ccflags-y += -DECM_CLASSIFIER_DSCP_DEBUG_LEVEL=1
ccflags-y += -DECM_CLASSIFIER_HYFI_DEBUG_LEVEL=1
ccflags-y += -DECM_CLASSIFIER_PCC_DEBUG_LEVEL=1
diff --git a/ecm_classifier.c b/ecm_classifier.c
index a6da26c..0dac519 100644
--- a/ecm_classifier.c
+++ b/ecm_classifier.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * 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.
@@ -50,6 +50,9 @@
#ifdef ECM_CLASSIFIER_PCC_ENABLE
#include "ecm_classifier_pcc.h"
#endif
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+#include "ecm_classifier_mark.h"
+#endif
/*
* ecm_classifier_assign_classifier()
@@ -115,6 +118,19 @@
return (struct ecm_classifier_instance *)chfi;
}
#endif
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+ if (type == ECM_CLASSIFIER_TYPE_MARK) {
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = ecm_classifier_mark_instance_alloc(ci);
+ if (!ecmi) {
+ DEBUG_TRACE("%p: Failed to create mark classifier\n", ci);
+ return NULL;
+ }
+ DEBUG_TRACE("%p: Created mark classifier: %p\n", ci, ecmi);
+ ecm_db_connection_classifier_assign(ci, (struct ecm_classifier_instance *)ecmi);
+ return (struct ecm_classifier_instance *)ecmi;
+ }
+#endif
DEBUG_ASSERT(NULL, "%p: Unsupported type: %d\n", ci, type);
return NULL;
diff --git a/ecm_classifier.h b/ecm_classifier.h
index b3dffe8..fdda166 100644
--- a/ecm_classifier.h
+++ b/ecm_classifier.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 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.
@@ -22,6 +22,9 @@
*/
enum ecm_classifier_types {
ECM_CLASSIFIER_TYPE_DEFAULT = 0, /* MUST BE FIRST, Default classifier */
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+ ECM_CLASSIFIER_TYPE_MARK, /* Mark classifier */
+#endif
#ifdef ECM_CLASSIFIER_HYFI_ENABLE
ECM_CLASSIFIER_TYPE_HYFI, /* HyFi classifier */
#endif
diff --git a/ecm_classifier_mark.c b/ecm_classifier_mark.c
new file mode 100644
index 0000000..92a9972
--- /dev/null
+++ b/ecm_classifier_mark.c
@@ -0,0 +1,786 @@
+/*
+ **************************************************************************
+ * Copyright (c) 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.
+ **************************************************************************
+ */
+
+/*
+ * Mark Classifier.
+ * This module provides an interface to customer's external module to interract with the ECM.
+ * It allows the customer to make smart decisions on the packets before offloading the connection to the
+ * acceleration engine.
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <linux/inet.h>
+#include <linux/in.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_MARK_DEBUG_LEVEL
+
+#include "ecm_types.h"
+#include "ecm_db_types.h"
+#include "ecm_state.h"
+#include "ecm_tracker.h"
+#include "ecm_classifier.h"
+#include "ecm_front_end_types.h"
+#include "ecm_tracker_datagram.h"
+#include "ecm_tracker_udp.h"
+#include "ecm_tracker_tcp.h"
+#include "ecm_db.h"
+#include "ecm_classifier_mark.h"
+#include "ecm_classifier_mark_public.h"
+#include "ecm_front_end_common.h"
+#include "ecm_front_end_ipv4.h"
+#ifdef ECM_IPV6_ENABLE
+#include "ecm_front_end_ipv6.h"
+#endif
+
+/*
+ * Magic numbers
+ */
+#define ECM_CLASSIFIER_MARK_INSTANCE_MAGIC 0x2567
+
+/*
+ * struct ecm_classifier_mark_instance
+ * State per connection for MARK classifier
+ */
+struct ecm_classifier_mark_instance {
+ struct ecm_classifier_instance base; /* Base type */
+
+ uint32_t ci_serial; /* RO: Serial of the connection */
+
+ struct ecm_classifier_mark_instance *next; /* Next classifier state instance (for accouting and reporting purposes) */
+ struct ecm_classifier_mark_instance *prev; /* Next classifier state instance (for accouting and reporting purposes) */
+
+ uint32_t mark; /* Mark value which this classifier extracted from the buffer */
+ struct ecm_classifier_process_response process_response;
+ /* Last process response computed */
+ int refs; /* Integer to trap we never go negative */
+#if (DEBUG_LEVEL > 0)
+ uint16_t magic;
+#endif
+};
+
+/*
+ * Operational control. By default it is disabled.
+ */
+static int ecm_classifier_mark_enabled; /* Operational behaviour */
+
+/*
+ * Management thread control
+ */
+static bool ecm_classifier_mark_terminate_pending; /* True when the user wants us to terminate */
+
+/*
+ * Debugfs dentry object.
+ */
+static struct dentry *ecm_classifier_mark_dentry;
+
+/*
+ * Locking of the classifier structures
+ */
+static DEFINE_SPINLOCK(ecm_classifier_mark_lock); /* Protect SMP access. */
+
+/*
+ * List of our classifier instances
+ */
+static struct ecm_classifier_mark_instance *ecm_classifier_mark_instances = NULL;
+ /* list of all active instances */
+static int ecm_classifier_mark_count = 0; /* Tracks number of instances allocated */
+
+/*
+ * Callbacks to the external modules.
+ */
+ecm_classifier_mark_get_callback_t mark_get_cb[ECM_CLASSIFIER_MARK_TYPE_MAX] = { NULL };
+ /* Callbacks which gets the mark from the packets */
+ecm_classifier_mark_sync_to_ipv4_callback_t sync_to_ipv4_cb[ECM_CLASSIFIER_MARK_TYPE_MAX] = { NULL };
+ /* Callbacks which syncs the IPv4 stats to the registered external subsystems */
+ecm_classifier_mark_sync_to_ipv6_callback_t sync_to_ipv6_cb[ECM_CLASSIFIER_MARK_TYPE_MAX] = { NULL };
+ /* Callbacks which syncs the IPv6 stats to the registered external subsystems */
+
+/*
+ * _ecm_classifier_mark_ref()
+ * Ref
+ */
+static void _ecm_classifier_mark_ref(struct ecm_classifier_mark_instance *ecmi)
+{
+ ecmi->refs++;
+ DEBUG_TRACE("%p: ecmi ref %d\n", ecmi, ecmi->refs);
+ DEBUG_ASSERT(ecmi->refs > 0, "%p: ref wrap\n", ecmi);
+}
+
+/*
+ * ecm_classifier_mark_ref()
+ * Ref
+ */
+static void ecm_classifier_mark_ref(struct ecm_classifier_instance *ci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)ci;
+
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ _ecm_classifier_mark_ref(ecmi);
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+}
+
+/*
+ * ecm_classifier_mark_deref()
+ * Deref
+ */
+static int ecm_classifier_mark_deref(struct ecm_classifier_instance *ci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)ci;
+
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecmi->refs--;
+ DEBUG_ASSERT(ecmi->refs >= 0, "%p: refs wrapped\n", ecmi);
+ DEBUG_TRACE("%p: Mark classifier deref %d\n", ecmi, ecmi->refs);
+ if (ecmi->refs) {
+ int refs = ecmi->refs;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ return refs;
+ }
+
+ /*
+ * Object to be destroyed
+ */
+ ecm_classifier_mark_count--;
+ DEBUG_ASSERT(ecm_classifier_mark_count >= 0, "%p: ecm_classifier_mark_count wrap\n", ecmi);
+
+ /*
+ * UnLink the instance from our list
+ */
+ if (ecmi->next) {
+ ecmi->next->prev = ecmi->prev;
+ }
+ if (ecmi->prev) {
+ ecmi->prev->next = ecmi->next;
+ } else {
+ DEBUG_ASSERT(ecm_classifier_mark_instances == ecmi, "%p: list bad %p\n", ecmi, ecm_classifier_mark_instances);
+ ecm_classifier_mark_instances = ecmi->next;
+ }
+ ecmi->next = NULL;
+ ecmi->prev = NULL;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+
+ /*
+ * Final
+ */
+ DEBUG_INFO("%p: Final mark classifier instance\n", ecmi);
+ kfree(ecmi);
+
+ return 0;
+}
+
+/*
+ * ecm_classifier_mark_process()
+ * Process new packet
+ *
+ * NOTE: This function would only ever be called if all other classifiers have failed.
+ */
+static void ecm_classifier_mark_process(struct ecm_classifier_instance *aci, ecm_tracker_sender_type_t sender,
+ struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb,
+ struct ecm_classifier_process_response *process_response)
+{
+ struct ecm_classifier_mark_instance *ecmi = (struct ecm_classifier_mark_instance *)aci;
+ ecm_classifier_mark_result_t result;
+ struct ecm_db_connection_instance *ci;
+ bool skb_header_adjusted = false;
+ uint32_t l2_encap_len;
+ uint16_t l2_encap_proto;
+ uint16_t skb_proto;
+ uint32_t mark = 0;
+ ecm_classifier_mark_get_callback_t cb = NULL;
+ ecm_classifier_mark_type_t type = ECM_CLASSIFIER_MARK_TYPE_L2_ENCAP;
+ /* TODO: By default we use this type. In the future the type will be gotten from the connection instance*/
+
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: invalid state magic\n", ecmi);
+
+ /*
+ * Not relevant to the connection if not enabled.
+ */
+ if (unlikely(!ecm_classifier_mark_enabled)) {
+ /*
+ * Not relevant.
+ */
+ DEBUG_WARN("%p: Mark classifier is not enabled.\n", aci);
+ goto not_relevant;
+ }
+
+ /*
+ * Get connection
+ */
+ ci = ecm_db_connection_serial_find_and_ref(ecmi->ci_serial);
+ if (!ci) {
+ /*
+ * Connection has gone from under us
+ */
+ DEBUG_WARN("%p: connection instance gone while processing classifier.\n", aci);
+ goto not_relevant;
+ }
+
+ /*
+ * Get the L2 encap protocol of the connection.
+ */
+ l2_encap_proto = ecm_db_connection_l2_encap_proto_get(ci);
+ if (!l2_encap_proto) {
+ /*
+ * The caller is not interested in the inspection. Not relevant.
+ */
+ DEBUG_WARN("%p: L2 encap protocol is zero.\n", aci);
+ ecm_db_connection_deref(ci);
+ goto not_relevant;
+ }
+
+ /*
+ * Is there an external callback to get the mark value from the packet?
+ */
+ rcu_read_lock();
+ cb = rcu_dereference(mark_get_cb[type]);
+ if (!cb) {
+ /*
+ * Not relevant.
+ */
+ rcu_read_unlock();
+ DEBUG_WARN("%p: No inspection callback set with type: %d.\n", aci, type);
+ ecm_db_connection_deref(ci);
+ goto not_relevant;
+ }
+
+ /*
+ * Before giving the skb to the external callback for getting the mark value,
+ * let's adjust the L2 encap header.
+ * If the skb's protocol is not equal to the connection's L2 encap protocol,
+ * this means the skb's L2 header is pulled off. So, let's push it back.
+ */
+ if (l2_encap_proto != ntohs(skb->protocol)) {
+ DEBUG_TRACE("%p: Connections L2 encap protocol: %x is different than skb's protocol: %x, need header adjustment.\n",
+ aci, l2_encap_proto, ntohs(skb->protocol));
+ l2_encap_len = ecm_front_end_l2_encap_header_len(l2_encap_proto);
+ skb_header_adjusted = true;
+ ecm_front_end_push_l2_encap_header(skb, l2_encap_len);
+ skb_proto = skb->protocol;
+ skb->protocol = htons(l2_encap_proto);
+ }
+
+ /*
+ * Call the external callback and get the result.
+ */
+ result = cb(skb, &mark);
+ rcu_read_unlock();
+
+ /*
+ * Pull the skb's L2 header, if it is adjusted in this classifier.
+ */
+ if (skb_header_adjusted) {
+ DEBUG_TRACE("%p: Adjust the L2 header back.\n", aci);
+ ecm_front_end_pull_l2_encap_header(skb, l2_encap_len);
+ skb->protocol = skb_proto;
+ }
+
+ /*
+ * Handle the result
+ */
+ switch (result) {
+ case ECM_CLASSIFIER_MARK_RESULT_NOT_YET:
+ /*
+ * Deny accel but don't change the permit state - we try again later
+ */
+ DEBUG_WARN("%p: External callback has not decided yet.\n", aci);
+ goto deny_accel;
+ case ECM_CLASSIFIER_MARK_RESULT_NOT_RELEVANT:
+ /*
+ * The callback told us that the classifier is not relevant to this connection.
+ */
+ DEBUG_WARN("%p: External callback decided not relevant.\n", aci);
+ ecm_db_connection_deref(ci);
+ goto not_relevant;
+ case ECM_CLASSIFIER_MARK_RESULT_SUCCESS:
+
+ /*
+ * Copy the returned mark value to the connection and the classifier instance.
+ * We copy the mark value to the classifier instance as well here for quick access
+ * in the sync functions.
+ */
+ DEBUG_WARN("%p: External callback returned the mark value: %x\n", aci, mark);
+ ecm_db_connection_mark_set(ci, mark);
+ ecmi->mark = mark;
+ break;
+ default:
+ DEBUG_ASSERT(false, "Unhandled result: %d\n", result);
+ }
+
+ /*
+ * Acceleration is permitted
+ */
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecmi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
+ ecmi->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
+ ecmi->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_ACCEL;
+ *process_response = ecmi->process_response;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ ecm_db_connection_deref(ci);
+
+ return;
+
+not_relevant:
+ /*
+ * ecm_classifier_mark_lock MUST be held
+ */
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecmi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
+ *process_response = ecmi->process_response;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ return;
+
+deny_accel:
+ /*
+ * ecm_classifier_mark_lock MUST be held
+ */
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecmi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
+ ecmi->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
+ ecmi->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_NO;
+ *process_response = ecmi->process_response;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ ecm_db_connection_deref(ci);
+}
+
+/*
+ * ecm_classifier_mark_type_get()
+ * Get type of classifier this is
+ */
+static ecm_classifier_type_t ecm_classifier_mark_type_get(struct ecm_classifier_instance *aci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+ return ECM_CLASSIFIER_TYPE_MARK;
+}
+
+/*
+ * ecm_classifier_mark_reclassify_allowed()
+ * Get whether reclassification is allowed
+ */
+static bool ecm_classifier_mark_reclassify_allowed(struct ecm_classifier_instance *aci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+ return true;
+}
+
+/*
+ * ecm_classifier_mark_reclassify()
+ * Reclassify
+ */
+static void ecm_classifier_mark_reclassify(struct ecm_classifier_instance *aci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+
+ /*
+ * Revert back to MAYBE relevant - we will evaluate when we get the next process() call.
+ */
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecmi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+}
+
+/*
+ * ecm_classifier_mark_last_process_response_get()
+ * Get result code returned by the last process call
+ */
+static void ecm_classifier_mark_last_process_response_get(struct ecm_classifier_instance *aci,
+ struct ecm_classifier_process_response *process_response)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ *process_response = ecmi->process_response;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+}
+
+/*
+ * ecm_classifier_mark_sync_to_v4()
+ * Front end is pushing accel engine state to us
+ */
+static void ecm_classifier_mark_sync_to_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
+{
+ int protocol;
+ int src_port;
+ int dst_port;
+ ip_addr_t src_ip;
+ ip_addr_t dst_ip;
+ __be32 src_ip4;
+ __be32 dest_ip4;
+ struct ecm_db_connection_instance *ci;
+ ecm_classifier_mark_sync_to_ipv4_callback_t cb = NULL;
+ ecm_classifier_mark_type_t type = ECM_CLASSIFIER_MARK_TYPE_L2_ENCAP;
+ /* TODO: By default we use this type. In the future the type will be gotten from the connection instance */
+ struct ecm_classifier_mark_instance *ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+
+ /*
+ * Nothing to update.
+ * We only care about flows that are actively being accelerated.
+ */
+ if (!(sync->flow_tx_packet_count || sync->return_tx_packet_count)) {
+ return;
+ }
+
+ /*
+ * Handle only the stats sync. We don't care about the evict or flush syncs.
+ */
+ if (sync->reason != ECM_FRONT_END_IPV4_RULE_SYNC_REASON_STATS) {
+ return;
+ }
+
+ ci = ecm_db_connection_serial_find_and_ref(ecmi->ci_serial);
+ if (!ci) {
+ DEBUG_TRACE("%p: No ci found for %u\n", ecmi, ecmi->ci_serial);
+ return;
+ }
+
+ protocol = ecm_db_connection_protocol_get(ci);
+ src_port = htons(ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_FROM));
+ dst_port = htons(ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_TO));
+ ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_FROM, src_ip);
+ ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_TO, dst_ip);
+
+ ecm_db_connection_deref(ci);
+
+ ECM_IP_ADDR_TO_NIN4_ADDR(src_ip4, src_ip);
+ ECM_IP_ADDR_TO_NIN4_ADDR(dest_ip4, dst_ip);
+
+ rcu_read_lock();
+ cb = rcu_dereference(sync_to_ipv4_cb[type]);
+ if (!cb) {
+ rcu_read_unlock();
+ DEBUG_WARN("%p: IPv4 mark sync callback is not set\n", ecmi);
+ return;
+ }
+
+ cb(ecmi->mark, src_ip4, src_port, dest_ip4, dst_port, protocol);
+ rcu_read_unlock();
+}
+
+/*
+ * ecm_classifier_mark_sync_from_v4()
+ * Front end is retrieving accel engine state from us
+ */
+static void ecm_classifier_mark_sync_from_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
+{
+ struct ecm_classifier_mark_instance *ecmi __attribute__((unused));
+
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+}
+
+/*
+ * ecm_classifier_mark_sync_to_v6()
+ * Front end is pushing accel engine state to us
+ */
+static void ecm_classifier_mark_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
+{
+ int protocol;
+ int src_port;
+ int dst_port;
+ ip_addr_t src_ip;
+ ip_addr_t dst_ip;
+ struct in6_addr src_ip6;
+ struct in6_addr dest_ip6;
+ struct ecm_db_connection_instance *ci;
+ ecm_classifier_mark_sync_to_ipv6_callback_t cb = NULL;
+ ecm_classifier_mark_type_t type = ECM_CLASSIFIER_MARK_TYPE_L2_ENCAP;
+ /* TODO: By default we use this type. In the future the type will be gotten from the connection instance */
+ struct ecm_classifier_mark_instance *ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+
+ /*
+ * Nothing to update.
+ * We only care about flows that are actively being accelerated.
+ */
+ if (!(sync->flow_tx_packet_count || sync->return_tx_packet_count)) {
+ return;
+ }
+
+ /*
+ * Handle only the stats sync. We don't care about the evict or flush syncs.
+ */
+ if (sync->reason != ECM_FRONT_END_IPV4_RULE_SYNC_REASON_STATS) {
+ return;
+ }
+
+ ci = ecm_db_connection_serial_find_and_ref(ecmi->ci_serial);
+ if (!ci) {
+ DEBUG_TRACE("%p: No ci found for %u\n", ecmi, ecmi->ci_serial);
+ return;
+ }
+
+ protocol = ecm_db_connection_protocol_get(ci);
+ src_port = htons(ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_FROM));
+ dst_port = htons(ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_TO));
+ ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_FROM, src_ip);
+ ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_TO, dst_ip);
+
+ ecm_db_connection_deref(ci);
+
+ ECM_IP_ADDR_TO_NIN6_ADDR(src_ip6, src_ip);
+ ECM_IP_ADDR_TO_NIN6_ADDR(dest_ip6, dst_ip);
+
+ rcu_read_lock();
+ cb = rcu_dereference(sync_to_ipv6_cb[type]);
+ if (!cb) {
+ rcu_read_unlock();
+ DEBUG_WARN("%p: IPv6 mark sync callback is not set\n", ecmi);
+ return;
+ }
+ cb(ecmi->mark, &src_ip6, src_port, &dest_ip6, dst_port, protocol);
+ rcu_read_unlock();
+}
+
+/*
+ * ecm_classifier_mark_sync_from_v6()
+ * Front end is retrieving accel engine state from us
+ */
+static void ecm_classifier_mark_sync_from_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
+{
+ struct ecm_classifier_mark_instance *ecmi __attribute__((unused));
+
+ ecmi = (struct ecm_classifier_mark_instance *)aci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+}
+
+#ifdef ECM_STATE_OUTPUT_ENABLE
+/*
+ * ecm_classifier_mark_state_get()
+ * Gets the state of this classfier and outputs it to debugfs.
+ */
+static int ecm_classifier_mark_state_get(struct ecm_classifier_instance *ci, struct ecm_state_file_instance *sfi)
+{
+ int result;
+ struct ecm_classifier_mark_instance *ecmi;
+ struct ecm_classifier_process_response process_response;
+ uint32_t mark;
+
+ ecmi = (struct ecm_classifier_mark_instance *)ci;
+ DEBUG_CHECK_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC, "%p: magic failed", ecmi);
+
+ if ((result = ecm_state_prefix_add(sfi, "mark"))) {
+ return result;
+ }
+
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ mark = ecmi->mark;
+ process_response = ecmi->process_response;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+
+ if ((result = ecm_state_write(sfi, "value", "%d", mark))) {
+ return result;
+ }
+
+ /*
+ * Output our last process response
+ */
+ if ((result = ecm_classifier_process_response_state_get(sfi, &process_response))) {
+ return result;
+ }
+
+ return ecm_state_prefix_remove(sfi);
+}
+#endif
+
+/*
+ * ecm_classifier_mark_instance_alloc()
+ * Allocate an instance of the mark classifier
+ */
+struct ecm_classifier_mark_instance *ecm_classifier_mark_instance_alloc(struct ecm_db_connection_instance *ci)
+{
+ struct ecm_classifier_mark_instance *ecmi;
+
+ /*
+ * Allocate the instance
+ */
+ ecmi = (struct ecm_classifier_mark_instance *)kzalloc(sizeof(struct ecm_classifier_mark_instance), GFP_ATOMIC | __GFP_NOWARN);
+ if (!ecmi) {
+ DEBUG_WARN("i%p: Failed to allocate Mark Classifier instance\n", ci);
+ return NULL;
+ }
+
+ DEBUG_SET_MAGIC(ecmi, ECM_CLASSIFIER_MARK_INSTANCE_MAGIC);
+ ecmi->refs = 1;
+
+ /*
+ * Methods generic to all classifiers.
+ */
+ ecmi->base.process = ecm_classifier_mark_process;
+ ecmi->base.sync_from_v4 = ecm_classifier_mark_sync_from_v4;
+ ecmi->base.sync_to_v4 = ecm_classifier_mark_sync_to_v4;
+ ecmi->base.sync_from_v6 = ecm_classifier_mark_sync_from_v6;
+ ecmi->base.sync_to_v6 = ecm_classifier_mark_sync_to_v6;
+ ecmi->base.type_get = ecm_classifier_mark_type_get;
+ ecmi->base.reclassify_allowed = ecm_classifier_mark_reclassify_allowed;
+ ecmi->base.reclassify = ecm_classifier_mark_reclassify;
+ ecmi->base.last_process_response_get = ecm_classifier_mark_last_process_response_get;
+#ifdef ECM_STATE_OUTPUT_ENABLE
+ ecmi->base.state_get = ecm_classifier_mark_state_get;
+#endif
+ ecmi->base.ref = ecm_classifier_mark_ref;
+ ecmi->base.deref = ecm_classifier_mark_deref;
+ ecmi->ci_serial = ecm_db_connection_serial_get(ci);
+
+ ecmi->process_response.process_actions = 0;
+ ecmi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE;
+
+ /*
+ * Final check if we are pending termination
+ */
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ if (ecm_classifier_mark_terminate_pending) {
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ DEBUG_WARN("%p: Terminating\n", ci);
+ kfree(ecmi);
+ return NULL;
+ }
+
+ /*
+ * Link the new instance into our list at the head
+ */
+ ecmi->next = ecm_classifier_mark_instances;
+ if (ecm_classifier_mark_instances) {
+ ecm_classifier_mark_instances->prev = ecmi;
+ }
+ ecm_classifier_mark_instances = ecmi;
+
+ /*
+ * Increment stats
+ */
+ ecm_classifier_mark_count++;
+ DEBUG_ASSERT(ecm_classifier_mark_count > 0, "%p: ecm_classifier_mark_count wrap for instance: %p\n", ci, ecmi);
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+
+ DEBUG_INFO("%p: Mark classifier instance alloc: %p\n", ci, ecmi);
+ return ecmi;
+}
+EXPORT_SYMBOL(ecm_classifier_mark_instance_alloc);
+
+/*
+ * ecm_classifier_mark_register_callbacks()
+ * Register external callbacks.
+ */
+int ecm_classifier_mark_register_callbacks(ecm_classifier_mark_type_t type,
+ ecm_classifier_mark_get_callback_t mark_get,
+ ecm_classifier_mark_sync_to_ipv4_callback_t sync_to_ipv4,
+ ecm_classifier_mark_sync_to_ipv6_callback_t sync_to_ipv6)
+{
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ if (ecm_classifier_mark_terminate_pending) {
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+ DEBUG_WARN("Terminating\n");
+ return -1;
+ }
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+
+ DEBUG_ASSERT(!mark_get_cb[type] && !sync_to_ipv4_cb[type] && !sync_to_ipv6_cb[type],
+ "Mark callbacks are already registered\n");
+ rcu_assign_pointer(mark_get_cb[type], mark_get);
+ rcu_assign_pointer(sync_to_ipv4_cb[type], sync_to_ipv4);
+ rcu_assign_pointer(sync_to_ipv6_cb[type], sync_to_ipv6);
+
+ return 0;
+}
+EXPORT_SYMBOL(ecm_classifier_mark_register_callbacks);
+
+/*
+ * ecm_classifier_mark_unregister_callbacks()
+ * Unregister external callbacks.
+ */
+void ecm_classifier_mark_unregister_callbacks(ecm_classifier_mark_type_t type)
+{
+ rcu_assign_pointer(mark_get_cb[type], NULL);
+ rcu_assign_pointer(sync_to_ipv4_cb[type], NULL);
+ rcu_assign_pointer(sync_to_ipv6_cb[type], NULL);
+
+}
+EXPORT_SYMBOL(ecm_classifier_mark_unregister_callbacks);
+
+/*
+ * ecm_classifier_mark_init()
+ */
+int ecm_classifier_mark_init(struct dentry *dentry)
+{
+ DEBUG_INFO("Mark classifier Module init\n");
+
+ ecm_classifier_mark_dentry = debugfs_create_dir("ecm_classifier_mark", dentry);
+ if (!ecm_classifier_mark_dentry) {
+ DEBUG_ERROR("Failed to create ecm mark directory in debugfs\n");
+ return -1;
+ }
+
+ if (!debugfs_create_u32("enabled", S_IRUGO | S_IWUSR, ecm_classifier_mark_dentry,
+ (u32 *)&ecm_classifier_mark_enabled)) {
+ DEBUG_ERROR("Failed to create mark enabled file in debugfs\n");
+ debugfs_remove_recursive(ecm_classifier_mark_dentry);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ecm_classifier_mark_init);
+
+/*
+ * ecm_classifier_mark_exit()
+ */
+void ecm_classifier_mark_exit(void)
+{
+ DEBUG_INFO("Mark classifier Module exit\n");
+
+ spin_lock_bh(&ecm_classifier_mark_lock);
+ ecm_classifier_mark_terminate_pending = true;
+ spin_unlock_bh(&ecm_classifier_mark_lock);
+
+ /*
+ * Remove the debugfs files recursively.
+ */
+ if (ecm_classifier_mark_dentry) {
+ debugfs_remove_recursive(ecm_classifier_mark_dentry);
+ }
+
+}
+EXPORT_SYMBOL(ecm_classifier_mark_exit);
diff --git a/ecm_classifier_mark.h b/ecm_classifier_mark.h
new file mode 100644
index 0000000..39693b8
--- /dev/null
+++ b/ecm_classifier_mark.h
@@ -0,0 +1,18 @@
+/*
+ **************************************************************************
+ * Copyright (c) 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.
+ **************************************************************************
+ */
+
+struct ecm_classifier_mark_instance;
+struct ecm_classifier_mark_instance *ecm_classifier_mark_instance_alloc(struct ecm_db_connection_instance *ci);
diff --git a/ecm_classifier_mark_public.h b/ecm_classifier_mark_public.h
new file mode 100644
index 0000000..d5351b4
--- /dev/null
+++ b/ecm_classifier_mark_public.h
@@ -0,0 +1,63 @@
+/*
+ **************************************************************************
+ * Copyright (c) 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.
+ **************************************************************************
+ */
+
+/*
+ * Mark types are used to register specific external mdoule callbacks to ECM.
+ * Each type of callback can process the packets based on its need.
+ */
+enum ecm_classifier_mark_types {
+ ECM_CLASSIFIER_MARK_TYPE_L2_ENCAP,
+ ECM_CLASSIFIER_MARK_TYPE_MAX
+};
+typedef enum ecm_classifier_mark_types ecm_classifier_mark_type_t;
+
+/*
+ * Result values of the external inspection module to the ECM's mark classifier.
+ * Based on the result the mark classifier takes the action for the inspected connection.
+ */
+enum ecm_classifier_mark_results {
+ ECM_CLASSIFIER_MARK_RESULT_NOT_YET, /* Classifier has not decided yet - try again later */
+ ECM_CLASSIFIER_MARK_RESULT_NOT_RELEVANT, /* Classifier is not relevant to this connection */
+ ECM_CLASSIFIER_MARK_RESULT_SUCCESS, /* Inspection is completed successfully */
+};
+typedef enum ecm_classifier_mark_results ecm_classifier_mark_result_t;
+
+/*
+ * Callback function which extracts a mark value from the skb and write it to the mark parameter.
+ */
+typedef ecm_classifier_mark_result_t (*ecm_classifier_mark_get_callback_t)(struct sk_buff *skb, uint32_t *mark);
+
+/*
+ * Callback functions which are called from the mark classifier's IPv4 and IPv6 sync_to
+ * functions to update the external modules.
+ */
+typedef void (*ecm_classifier_mark_sync_to_ipv4_callback_t)(uint32_t mark,
+ __be32 src_ip, int src_port,
+ __be32 dest_ip, int dest_port,
+ int protocol);
+typedef void (*ecm_classifier_mark_sync_to_ipv6_callback_t)(uint32_t mark,
+ struct in6_addr *src_ip, int src_port,
+ struct in6_addr *dest_ip, int dest_port,
+ int protocol);
+
+/*
+ * Register/Unregister callback functions which are called from the external modules.
+ */
+extern int ecm_classifier_mark_register_callbacks(ecm_classifier_mark_type_t type, ecm_classifier_mark_get_callback_t mark_get,
+ ecm_classifier_mark_sync_to_ipv4_callback_t sync_to_ipv4,
+ ecm_classifier_mark_sync_to_ipv6_callback_t sync_to_ipv6);
+extern void ecm_classifier_mark_unregister_callbacks(ecm_classifier_mark_type_t type);
+
diff --git a/ecm_db/ecm_db_connection.c b/ecm_db/ecm_db_connection.c
index a316e4d..697fb8f 100644
--- a/ecm_db/ecm_db_connection.c
+++ b/ecm_db/ecm_db_connection.c
@@ -180,6 +180,65 @@
EXPORT_SYMBOL(ecm_db_connection_count_by_protocol_get);
/*
+ * ecm_db_connection_l2_encap_proto_set()
+ * Sets the L2 encap protocol.
+ */
+void ecm_db_connection_l2_encap_proto_set(struct ecm_db_connection_instance *ci, uint16_t l2_encap_proto)
+{
+ DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
+
+ spin_lock_bh(&ecm_db_lock);
+ ci->l2_encap_proto = l2_encap_proto;
+ spin_unlock_bh(&ecm_db_lock);
+}
+
+/*
+ * ecm_db_connection_l2_encap_proto_get()
+ * Gets the L2 encap protocol.
+ */
+uint16_t ecm_db_connection_l2_encap_proto_get(struct ecm_db_connection_instance *ci)
+{
+ uint16_t proto;
+ DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
+
+ spin_lock_bh(&ecm_db_lock);
+ proto = ci->l2_encap_proto;
+ spin_unlock_bh(&ecm_db_lock);
+
+ return proto;
+}
+
+/*
+ * ecm_db_connection_mark_set()
+ * Sets the mark value of the connection.
+ */
+void ecm_db_connection_mark_set(struct ecm_db_connection_instance *ci, uint32_t mark)
+{
+ DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
+
+ spin_lock_bh(&ecm_db_lock);
+ ci->mark = mark;
+ spin_unlock_bh(&ecm_db_lock);
+
+}
+
+/*
+ * ecm_db_connection_mark_get()
+ * Gets the mark value of the connection.
+ */
+uint32_t ecm_db_connection_mark_get(struct ecm_db_connection_instance *ci)
+{
+ uint16_t mark;
+ DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
+
+ spin_lock_bh(&ecm_db_lock);
+ mark = ci->mark;
+ spin_unlock_bh(&ecm_db_lock);
+
+ return mark;
+}
+
+/*
* ecm_db_connection_front_end_get_and_ref()
* Return ref to the front end instance of the connection
*/
diff --git a/ecm_db/ecm_db_connection.h b/ecm_db/ecm_db_connection.h
index a1cbd78..b8c014a 100644
--- a/ecm_db/ecm_db_connection.h
+++ b/ecm_db/ecm_db_connection.h
@@ -61,6 +61,8 @@
int protocol; /* RO: Protocol of the connection */
ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
bool is_routed; /* RO: True when connection is routed, false when not */
+ uint16_t l2_encap_proto; /* L2 encap protocol of the flow of this connection */
+ uint32_t mark; /* The result value of mark classifier on this connection */
/*
* Connection endpoint mapping
@@ -356,5 +358,10 @@
void ecm_db_front_end_instance_ref_and_set(struct ecm_db_connection_instance *ci,
struct ecm_front_end_connection_instance *feci);
+void ecm_db_connection_l2_encap_proto_set(struct ecm_db_connection_instance *ci, uint16_t l2_encap_proto);
+uint16_t ecm_db_connection_l2_encap_proto_get(struct ecm_db_connection_instance *ci);
+void ecm_db_connection_mark_set(struct ecm_db_connection_instance *ci, uint32_t mark);
+uint32_t ecm_db_connection_mark_get(struct ecm_db_connection_instance *ci);
+
bool ecm_db_connection_init(struct dentry *dentry);
void ecm_db_connection_exit(void);
diff --git a/ecm_init.c b/ecm_init.c
index 68ee556..c8ef5bd 100644
--- a/ecm_init.c
+++ b/ecm_init.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-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.
@@ -59,6 +59,11 @@
extern int ecm_classifier_default_init(struct dentry *dentry);
extern void ecm_classifier_default_exit(void);
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+extern int ecm_classifier_mark_init(struct dentry *dentry);
+extern void ecm_classifier_mark_exit(void);
+#endif
+
#ifdef ECM_CLASSIFIER_NL_ENABLE
extern int ecm_classifier_nl_rules_init(struct dentry *dentry);
extern void ecm_classifier_nl_rules_exit(void);
@@ -139,6 +144,12 @@
goto err_cls_pcc;
}
#endif
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+ ret = ecm_classifier_mark_init(ecm_dentry);
+ if (0 != ret) {
+ goto err_cls_mark;
+ }
+#endif
ret = ecm_interface_init();
if (0 != ret) {
@@ -196,6 +207,10 @@
#endif
ecm_interface_exit();
err_iface:
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+ ecm_classifier_mark_exit();
+err_cls_mark:
+#endif
#ifdef ECM_CLASSIFIER_PCC_ENABLE
ecm_classifier_pcc_exit();
err_cls_pcc:
@@ -281,6 +296,10 @@
DEBUG_INFO("exit nl classifier\n");
ecm_classifier_nl_rules_exit();
#endif
+#ifdef ECM_CLASSIFIER_MARK_ENABLE
+ DEBUG_INFO("exit mark classifier\n");
+ ecm_classifier_mark_exit();
+#endif
DEBUG_INFO("exit default classifier\n");
ecm_classifier_default_exit();
DEBUG_INFO("exit db\n");
diff --git a/frontends/include/ecm_front_end_common.h b/frontends/include/ecm_front_end_common.h
index ca3a35a..cf2aa3e 100644
--- a/frontends/include/ecm_front_end_common.h
+++ b/frontends/include/ecm_front_end_common.h
@@ -50,10 +50,10 @@
* ecm_front_end_l2_encap_header_len()
* Return length of encapsulating L2 header
*/
-static inline uint32_t ecm_front_end_l2_encap_header_len(struct sk_buff *skb)
+static inline uint32_t ecm_front_end_l2_encap_header_len(uint16_t protocol)
{
- switch (skb->protocol) {
- case ntohs(ETH_P_PPP_SES):
+ switch (protocol) {
+ case ETH_P_PPP_SES:
return PPPOE_SES_HLEN;
default:
return 0;
diff --git a/frontends/nss/ecm_nss_ipv4.c b/frontends/nss/ecm_nss_ipv4.c
index 7077f58..a521b3a 100644
--- a/frontends/nss/ecm_nss_ipv4.c
+++ b/frontends/nss/ecm_nss_ipv4.c
@@ -941,7 +941,7 @@
*/
static unsigned int ecm_nss_ipv4_ip_process(struct net_device *out_dev, struct net_device *in_dev,
uint8_t *src_node_addr, uint8_t *dest_node_addr,
- bool can_accel, bool is_routed, bool is_l2_encap, struct sk_buff *skb)
+ bool can_accel, bool is_routed, bool is_l2_encap, struct sk_buff *skb, uint16_t l2_encap_proto)
{
struct ecm_tracker_ip_header ip_hdr;
struct nf_conn *ct;
@@ -1428,7 +1428,7 @@
&ip_hdr,
ct, sender, ecm_dir,
&orig_tuple, &reply_tuple,
- ip_src_addr, ip_dest_addr, ip_src_addr_nat, ip_dest_addr_nat);
+ ip_src_addr, ip_dest_addr, ip_src_addr_nat, ip_dest_addr_nat, l2_encap_proto);
}
#ifdef ECM_NON_PORTED_SUPPORT_ENABLE
return ecm_nss_non_ported_ipv4_process(out_dev, out_dev_nat,
@@ -1439,7 +1439,7 @@
&ip_hdr,
ct, sender, ecm_dir,
&orig_tuple, &reply_tuple,
- ip_src_addr, ip_dest_addr, ip_src_addr_nat, ip_dest_addr_nat);
+ ip_src_addr, ip_dest_addr, ip_src_addr_nat, ip_dest_addr_nat, l2_encap_proto);
#else
return NF_ACCEPT;
#endif
@@ -1535,7 +1535,7 @@
DEBUG_TRACE("Post routing process skb %p, out: %p (%s), in: %p (%s)\n", skb, out, out->name, in, in->name);
result = ecm_nss_ipv4_ip_process((struct net_device *)out, in, NULL, NULL,
- can_accel, true, false, skb);
+ can_accel, true, false, skb, 0);
dev_put(in);
return result;
}
@@ -1561,13 +1561,13 @@
return NF_ACCEPT;
}
- encap_header_len = ecm_front_end_l2_encap_header_len(skb);
+ encap_header_len = ecm_front_end_l2_encap_header_len(ntohs(skb->protocol));
ecm_front_end_pull_l2_encap_header(skb, encap_header_len);
skb->protocol = htons(ETH_P_IP);
result = ecm_nss_ipv4_ip_process(out, in, skb_eth_hdr->h_source,
skb_eth_hdr->h_dest, can_accel,
- false, true, skb);
+ false, true, skb, ETH_P_PPP_SES);
ecm_front_end_push_l2_encap_header(skb, encap_header_len);
skb->protocol = htons(ETH_P_PPP_SES);
@@ -1741,7 +1741,7 @@
}
result = ecm_nss_ipv4_ip_process((struct net_device *)out, in,
- skb_eth_hdr->h_source, skb_eth_hdr->h_dest, can_accel, false, false, skb);
+ skb_eth_hdr->h_source, skb_eth_hdr->h_dest, can_accel, false, false, skb, 0);
dev_put(in);
dev_put(bridge);
diff --git a/frontends/nss/ecm_nss_ipv6.c b/frontends/nss/ecm_nss_ipv6.c
index 7a0b8b8..c6c631f 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -872,7 +872,7 @@
static unsigned int ecm_nss_ipv6_ip_process(struct net_device *out_dev, struct net_device *in_dev,
uint8_t *src_node_addr, uint8_t *dest_node_addr,
bool can_accel, bool is_routed, bool is_l2_encap,
- struct sk_buff *skb)
+ struct sk_buff *skb, uint16_t l2_encap_proto)
{
struct ecm_tracker_ip_header ip_hdr;
struct nf_conn *ct;
@@ -1109,7 +1109,7 @@
&ip_hdr,
ct, sender, ecm_dir,
&orig_tuple, &reply_tuple,
- ip_src_addr, ip_dest_addr);
+ ip_src_addr, ip_dest_addr, l2_encap_proto);
}
#ifdef ECM_NON_PORTED_SUPPORT_ENABLE
return ecm_nss_non_ported_ipv6_process(out_dev, in_dev,
@@ -1119,7 +1119,7 @@
&ip_hdr,
ct, sender, ecm_dir,
&orig_tuple, &reply_tuple,
- ip_src_addr, ip_dest_addr);
+ ip_src_addr, ip_dest_addr, l2_encap_proto);
#else
return NF_ACCEPT;
#endif
@@ -1213,7 +1213,7 @@
}
DEBUG_TRACE("Post routing process skb %p, out: %p, in: %p\n", skb, out, in);
- result = ecm_nss_ipv6_ip_process((struct net_device *)out, in, NULL, NULL, can_accel, true, false, skb);
+ result = ecm_nss_ipv6_ip_process((struct net_device *)out, in, NULL, NULL, can_accel, true, false, skb, 0);
dev_put(in);
return result;
}
@@ -1239,13 +1239,13 @@
return NF_ACCEPT;
}
- encap_header_len = ecm_front_end_l2_encap_header_len(skb);
+ encap_header_len = ecm_front_end_l2_encap_header_len(ntohs(skb->protocol));
ecm_front_end_pull_l2_encap_header(skb, encap_header_len);
skb->protocol = htons(ETH_P_IPV6);
result = ecm_nss_ipv6_ip_process(out, in, skb_eth_hdr->h_source,
skb_eth_hdr->h_dest, can_accel,
- false, true, skb);
+ false, true, skb, ETH_P_PPP_SES);
ecm_front_end_push_l2_encap_header(skb, encap_header_len);
skb->protocol = htons(ETH_P_PPP_SES);
@@ -1420,7 +1420,7 @@
}
result = ecm_nss_ipv6_ip_process((struct net_device *)out, in,
- skb_eth_hdr->h_source, skb_eth_hdr->h_dest, can_accel, false, false, skb);
+ skb_eth_hdr->h_source, skb_eth_hdr->h_dest, can_accel, false, false, skb, 0);
dev_put(in);
dev_put(bridge);
diff --git a/frontends/nss/ecm_nss_non_ported_ipv4.c b/frontends/nss/ecm_nss_non_ported_ipv4.c
index 7eae2d0..8f6212a 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_non_ported_ipv4.c
@@ -1876,7 +1876,8 @@
struct ecm_tracker_ip_header *ip_hdr,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat)
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat,
+ uint16_t l2_encap_proto)
{
struct ecm_db_connection_instance *ci;
int protocol;
@@ -2118,6 +2119,8 @@
ecm_db_front_end_instance_ref_and_set(nci, feci);
+ ecm_db_connection_l2_encap_proto_set(nci, l2_encap_proto);
+
/*
* Now add the connection into the database.
* NOTE: In an SMP situation such as ours there is a possibility that more than one packet for the same
diff --git a/frontends/nss/ecm_nss_non_ported_ipv4.h b/frontends/nss/ecm_nss_non_ported_ipv4.h
index 9ddb747..2b97d78 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv4.h
+++ b/frontends/nss/ecm_nss_non_ported_ipv4.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 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.
@@ -22,6 +22,7 @@
struct ecm_tracker_ip_header *ip_hdr,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat);
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat,
+ uint16_t l2_encap_proto);
extern bool ecm_nss_non_ported_ipv4_debugfs_init(struct dentry *dentry);
diff --git a/frontends/nss/ecm_nss_non_ported_ipv6.c b/frontends/nss/ecm_nss_non_ported_ipv6.c
index 048f62a..7ab0114 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv6.c
+++ b/frontends/nss/ecm_nss_non_ported_ipv6.c
@@ -1674,7 +1674,7 @@
struct ecm_tracker_ip_header *ip_hdr,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr)
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, uint16_t l2_encap_proto)
{
struct ecm_db_connection_instance *ci;
int protocol;
@@ -1858,6 +1858,8 @@
ecm_db_front_end_instance_ref_and_set(nci, feci);
+ ecm_db_connection_l2_encap_proto_set(nci, l2_encap_proto);
+
/*
* Now add the connection into the database.
* NOTE: In an SMP situation such as ours there is a possibility that more than one packet for the same
diff --git a/frontends/nss/ecm_nss_non_ported_ipv6.h b/frontends/nss/ecm_nss_non_ported_ipv6.h
index 5f02c58..82667f7 100644
--- a/frontends/nss/ecm_nss_non_ported_ipv6.h
+++ b/frontends/nss/ecm_nss_non_ported_ipv6.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 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.
@@ -22,6 +22,6 @@
struct ecm_tracker_ip_header *ip_hdr,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr);
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, uint16_t l2_encap_proto);
extern bool ecm_nss_non_ported_ipv6_debugfs_init(struct dentry *dentry);
diff --git a/frontends/nss/ecm_nss_ported_ipv4.c b/frontends/nss/ecm_nss_ported_ipv4.c
index 23dbefd..cb9b122 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_ported_ipv4.c
@@ -1864,7 +1864,7 @@
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr,
- ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat)
+ ip_addr_t ip_src_addr_nat, ip_addr_t ip_dest_addr_nat, uint16_t l2_encap_proto)
{
struct tcphdr *tcp_hdr;
struct tcphdr tcp_hdr_buff;
@@ -2250,6 +2250,8 @@
ecm_db_front_end_instance_ref_and_set(nci, feci);
+ ecm_db_connection_l2_encap_proto_set(nci, l2_encap_proto);
+
/*
* Now add the connection into the database.
* NOTE: In an SMP situation such as ours there is a possibility that more than one packet for the same
diff --git a/frontends/nss/ecm_nss_ported_ipv4.h b/frontends/nss/ecm_nss_ported_ipv4.h
index 7b0577b..dfcf02a 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.h
+++ b/frontends/nss/ecm_nss_ported_ipv4.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 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.
@@ -23,6 +23,6 @@
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, ip_addr_t ip_src_addr_nat,
- ip_addr_t ip_dest_addr_nat);
+ ip_addr_t ip_dest_addr_nat, uint16_t l2_encap_proto);
extern bool ecm_nss_ported_ipv4_debugfs_init(struct dentry *dentry);
diff --git a/frontends/nss/ecm_nss_ported_ipv6.c b/frontends/nss/ecm_nss_ported_ipv6.c
index 5486550..df8820e 100644
--- a/frontends/nss/ecm_nss_ported_ipv6.c
+++ b/frontends/nss/ecm_nss_ported_ipv6.c
@@ -1754,7 +1754,7 @@
struct ecm_tracker_ip_header *iph,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr)
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, uint16_t l2_encap_proto)
{
struct tcphdr *tcp_hdr;
struct tcphdr tcp_hdr_buff;
@@ -2054,6 +2054,8 @@
ecm_db_front_end_instance_ref_and_set(nci, feci);
+ ecm_db_connection_l2_encap_proto_set(nci, l2_encap_proto);
+
/*
* Now add the connection into the database.
* NOTE: In an SMP situation such as ours there is a possibility that more than one packet for the same
diff --git a/frontends/nss/ecm_nss_ported_ipv6.h b/frontends/nss/ecm_nss_ported_ipv6.h
index 5e2a9cf..ad8a933 100644
--- a/frontends/nss/ecm_nss_ported_ipv6.h
+++ b/frontends/nss/ecm_nss_ported_ipv6.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 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.
@@ -22,6 +22,6 @@
struct ecm_tracker_ip_header *iph,
struct nf_conn *ct, ecm_tracker_sender_type_t sender, ecm_db_direction_t ecm_dir,
struct nf_conntrack_tuple *orig_tuple, struct nf_conntrack_tuple *reply_tuple,
- ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr);
+ ip_addr_t ip_src_addr, ip_addr_t ip_dest_addr, uint16_t l2_encap_proto);
extern bool ecm_nss_ported_ipv6_debugfs_init(struct dentry *dentry);