[qca-nss-sfe] SAWF related changes in SFE.

1. Adding sawf_metadata in SFE connection information
2. Addition of per cpu per service class stats DB as part of SFE.

Change-Id: I44e2a0d7b6144ee28a24fc5edd21fdc1cd439142
Signed-off-by: Parikshit Gune <quic_pgune@quicinc.com>
diff --git a/sfe_ipv4.c b/sfe_ipv4.c
index 3b3d1cb..b5416d0 100644
--- a/sfe_ipv4.c
+++ b/sfe_ipv4.c
@@ -32,6 +32,7 @@
 #include <linux/netfilter.h>
 #include <linux/inetdevice.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/seqlock.h>
 #include <net/protocol.h>
 #include <net/gre.h>
 
@@ -733,6 +734,21 @@
 }
 
 /*
+ * sfe_ipv4_service_class_stats_inc()
+ *	Increment per cpu per service class stats.
+ */
+void sfe_ipv4_service_class_stats_inc(struct sfe_ipv4 *si, uint8_t sid, uint64_t bytes)
+{
+	struct sfe_ipv4_service_class_stats_db *sc_stats_db = this_cpu_ptr(si->stats_pcpu_psc);
+	struct sfe_ipv4_per_service_class_stats *sc_stats = &sc_stats_db->psc_stats[sid];
+
+	write_seqcount_begin(&sc_stats->seq);
+	sc_stats->tx_bytes += bytes;
+	sc_stats->tx_packets++;
+	write_seqcount_end(&sc_stats->seq);
+}
+
+/*
  * sfe_ipv4_exception_stats_inc()
  *	Increment exception stats.
  */
@@ -1055,6 +1071,8 @@
 	struct net *net;
 	struct sock *sk;
 	unsigned int src_if_idx;
+	u32 flow_sawf_tag;
+	u32 return_sawf_tag;
 
 	if (msg->rule_flags & SFE_RULE_CREATE_FLAG_USE_FLOW_BOTTOM_INTERFACE) {
 		flow_interface_num = msg->conn_rule.flow_interface_num;
@@ -1232,6 +1250,17 @@
 	}
 
 	/*
+	 * Mark SAWF metadata if the sawf tag is valid and set.
+	 */
+	original_cm->sawf_valid = false;
+	flow_sawf_tag = SFE_GET_SAWF_TAG(msg->sawf_rule.flow_mark);
+	if (likely(SFE_SAWF_TAG_IS_VALID(flow_sawf_tag))) {
+		original_cm->mark = msg->sawf_rule.flow_mark;
+		original_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
+		original_cm->sawf_valid = true;
+	}
+
+	/*
 	 * Add VLAN rule to original_cm
 	 */
 	if (msg->valid_flags & SFE_RULE_CREATE_VLAN_VALID) {
@@ -1435,6 +1464,17 @@
 	}
 
 	/*
+	 * Mark SAWF metadata in reply match if the sawf tag is valid.
+	 */
+	reply_cm->sawf_valid = false;
+	return_sawf_tag = SFE_GET_SAWF_TAG(msg->sawf_rule.return_mark);
+	if (likely(SFE_SAWF_TAG_IS_VALID(return_sawf_tag))) {
+		reply_cm->mark = msg->sawf_rule.return_mark;
+		reply_cm->flags |= SFE_IPV4_CONNECTION_MATCH_FLAG_MARK;
+		reply_cm->sawf_valid = true;
+	}
+
+	/*
 	 * Setup UDP Socket if found to be valid for decap.
 	 */
 	RCU_INIT_POINTER(reply_cm->up, NULL);
@@ -1991,6 +2031,9 @@
 	u64 dest_rx_bytes;
 	u64 last_sync_jiffies;
 	u32 src_mark, dest_mark, src_priority, dest_priority, src_dscp, dest_dscp;
+	bool original_cm_sawf_valid, reply_cm_sawf_valid;
+	u32 flow_service_class, return_service_class;
+	u32 flow_msduq, return_msduq;
 	u32 packet, byte, original_cm_flags;
 	u16 pppoe_session_id;
 	u8 pppoe_remote_mac[ETH_ALEN];
@@ -2051,7 +2094,12 @@
 	original_cm_flags = original_cm->flags;
 	pppoe_session_id = original_cm->pppoe_session_id;
 	ether_addr_copy(pppoe_remote_mac, original_cm->pppoe_remote_mac);
-
+	original_cm_sawf_valid = original_cm->sawf_valid;
+	reply_cm_sawf_valid = reply_cm->sawf_valid;
+	flow_service_class = SFE_GET_SAWF_SERVICE_CLASS(original_cm->mark);
+	flow_msduq = SFE_GET_SAWF_MSDUQ(original_cm->mark);
+	return_service_class = SFE_GET_SAWF_SERVICE_CLASS(reply_cm->mark);
+	return_msduq = SFE_GET_SAWF_MSDUQ(reply_cm->mark);
 #ifdef CONFIG_NF_FLOW_COOKIE
 	src_flow_cookie = original_cm->flow_cookie;
 	dst_flow_cookie = reply_cm->flow_cookie;
@@ -2103,6 +2151,16 @@
 				pppoe_session_id, pppoe_remote_mac);
 	}
 
+	if (original_cm_sawf_valid) {
+		bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "flow_service_class=\"%d\" flow_msduq=\"%d\" ",
+				flow_service_class, flow_msduq);
+	}
+
+	if (reply_cm_sawf_valid) {
+		bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "return_service_class=\"%d\" return_msduq=\"%d\" ",
+				return_service_class, return_msduq);
+	}
+
 	bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "/>\n");
 
 	if (copy_to_user(buffer + *total_read, msg, CHAR_DEV_MSG_SIZE)) {
@@ -2553,12 +2611,22 @@
 	}
 
 	/*
+	 * Allocate per cpu per service class memory.
+	 */
+	si->stats_pcpu_psc = alloc_percpu_gfp(struct sfe_ipv4_service_class_stats_db,
+						GFP_KERNEL | __GFP_ZERO);
+	if (!si->stats_pcpu_psc) {
+		DEBUG_ERROR("failed to allocate per cpu per service clas stats memory\n");
+		goto exit1;
+	}
+
+	/*
 	 * Create sys/sfe_ipv4
 	 */
 	si->sys_ipv4 = kobject_create_and_add("sfe_ipv4", NULL);
 	if (!si->sys_ipv4) {
 		DEBUG_ERROR("failed to register sfe_ipv4\n");
-		goto exit1;
+		goto exit2;
 	}
 
 	/*
@@ -2567,20 +2635,20 @@
 	result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
 	if (result) {
 		DEBUG_ERROR("failed to register debug dev file: %d\n", result);
-		goto exit2;
+		goto exit3;
 	}
 
 	result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
 	if (result) {
 		DEBUG_ERROR("failed to register debug dev file: %d\n", result);
-		goto exit3;
+		goto exit4;
 	}
 
 #ifdef CONFIG_NF_FLOW_COOKIE
 	result = sysfs_create_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
 	if (result) {
 		DEBUG_ERROR("failed to register flow cookie enable file: %d\n", result);
-		goto exit4;
+		goto exit5;
 	}
 #endif /* CONFIG_NF_FLOW_COOKIE */
 
@@ -2592,7 +2660,7 @@
 #endif
 	if (result < 0) {
 		DEBUG_ERROR("can't register nf local out hook: %d\n", result);
-		goto exit5;
+		goto exit6;
 	}
 	DEBUG_INFO("Register nf local out hook success: %d\n", result);
 #endif
@@ -2602,7 +2670,7 @@
 	result = register_chrdev(0, "sfe_ipv4", &sfe_ipv4_debug_dev_fops);
 	if (result < 0) {
 		DEBUG_ERROR("Failed to register chrdev: %d\n", result);
-		goto exit6;
+		goto exit7;
 	}
 
 	si->debug_dev = result;
@@ -2617,7 +2685,7 @@
 	spin_lock_init(&si->lock);
 	return 0;
 
-exit6:
+exit7:
 #ifdef SFE_PROCESS_LOCAL_OUT
 	DEBUG_TRACE("sfe: Unregister local out hook\n");
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
@@ -2625,20 +2693,23 @@
 #else
 	nf_unregister_net_hooks(&init_net, sfe_ipv4_ops_local_out, ARRAY_SIZE(sfe_ipv4_ops_local_out));
 #endif
-exit5:
+exit6:
 #endif
 #ifdef CONFIG_NF_FLOW_COOKIE
 	sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_flow_cookie_attr.attr);
 
-exit4:
+exit5:
 #endif /* CONFIG_NF_FLOW_COOKIE */
 	sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_cpu_attr.attr);
-exit3:
+exit4:
 	sysfs_remove_file(si->sys_ipv4, &sfe_ipv4_debug_dev_attr.attr);
 
-exit2:
+exit3:
 	kobject_put(si->sys_ipv4);
 
+exit2:
+	free_percpu(si->stats_pcpu_psc);
+
 exit1:
 	free_percpu(si->stats_pcpu);
 
@@ -2682,6 +2753,7 @@
 	kobject_put(si->sys_ipv4);
 
 	free_percpu(si->stats_pcpu);
+	free_percpu(si->stats_pcpu_psc);
 }
 
 #ifdef CONFIG_NF_FLOW_COOKIE