[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/exports/sfe_api.h b/exports/sfe_api.h
index da9c857..a5fcf95 100644
--- a/exports/sfe_api.h
+++ b/exports/sfe_api.h
@@ -23,6 +23,9 @@
#define SFE_MAX_VLAN_DEPTH 2
#define SFE_VLAN_ID_NOT_CONFIGURED 0xfff
+#define SFE_MAX_SERVICE_CLASS_ID 0x80
+#define SFE_INVALID_SERVICE_CLASS_ID 0xff
+#define SFE_INVALID_MSDUQ 0xff
#define SFE_SPECIAL_INTERFACE_BASE 0x7f00
#define SFE_SPECIAL_INTERFACE_IPV4 (SFE_SPECIAL_INTERFACE_BASE + 1)
@@ -247,6 +250,15 @@
};
/**
+ * sfe_service_class_rule
+ * SFE service class rule information in both direction.
+ */
+struct sfe_service_class_rule {
+ uint32_t flow_mark; /**< Service class information in flow direction */
+ uint32_t return_mark; /**< Service class information in return direction */
+};
+
+/**
* The IPv4 rule create sub-message structure.
*/
struct sfe_ipv4_rule_create_msg {
@@ -269,6 +281,8 @@
struct sfe_acceleration_direction_rule direction_rule;/* Direction related accleration parameters*/
#endif
/* Response */
+ struct sfe_service_class_rule sawf_rule;
+ /**< Service class related information */
u32 index; /**< Slot ID for cache stats to host OS */
};
@@ -392,6 +406,7 @@
/*
* Response
*/
+ struct sfe_service_class_rule sawf_rule; /**< Service class related information */
u32 index; /**< Slot ID for cache stats to host OS */
};
diff --git a/sfe.h b/sfe.h
index 6cadbfe..e1fe4ec 100644
--- a/sfe.h
+++ b/sfe.h
@@ -34,6 +34,23 @@
#define SFE_L2_PARSE_FLAGS_PPPOE_INGRESS 0x01 /* Indicates presence of a valid PPPoE header */
+/**
+ * SAWF_metadata information placement in mark field.
+ */
+#define SFE_SAWF_VALID_TAG 0xAA
+#define SFE_SAWF_TAG_SHIFT 0x18
+#define SFE_SAWF_SERVICE_CLASS_SHIFT 0x10
+#define SFE_SAWF_SERVICE_CLASS_MASK 0xff
+#define SFE_SAWF_MSDUQ_MASK 0xffff
+
+/**
+ * SAWF_metadata extraction.
+ */
+#define SFE_GET_SAWF_TAG(x) (x>>SFE_SAWF_TAG_SHIFT)
+#define SFE_GET_SAWF_SERVICE_CLASS(x) ((x>>SFE_SAWF_SERVICE_CLASS_SHIFT) & SFE_SAWF_SERVICE_CLASS_MASK)
+#define SFE_GET_SAWF_MSDUQ(x) (x & SFE_SAWF_MSDUQ_MASK)
+#define SFE_SAWF_TAG_IS_VALID(x) ((x == SFE_SAWF_VALID_TAG) ? true : false)
+
/*
* IPv6 address structure
*/
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
diff --git a/sfe_ipv4.h b/sfe_ipv4.h
index 865a93d..428af90 100644
--- a/sfe_ipv4.h
+++ b/sfe_ipv4.h
@@ -194,6 +194,7 @@
* xmit device's feature
*/
netdev_features_t features;
+ bool sawf_valid; /* Indicates mark has valid SAWF information */
};
/*
@@ -323,6 +324,28 @@
};
/*
+ * sfe_ipv4_per_service_class_stats
+ * Per service class stats
+ */
+struct sfe_ipv4_per_service_class_stats {
+ u64 tx_bytes; /* Byte count */
+ u64 tx_packets; /* Packet count */
+ seqcount_t seq; /* seq lock for read/write protection */
+ /*
+ * TODO : add entries to be collected later.
+ */
+};
+
+/*
+ * sfe_ipv4_service_class_stats_db
+ * stat entries for each service class.
+ */
+struct sfe_ipv4_service_class_stats_db {
+ struct sfe_ipv4_per_service_class_stats psc_stats[SFE_MAX_SERVICE_CLASS_ID];
+ /* Per service class stats */
+};
+
+/*
* Per-module structure.
*/
struct sfe_ipv4 {
@@ -351,6 +374,8 @@
int flow_cookie_enable;
/* Enable/disable flow cookie at runtime */
#endif
+ struct sfe_ipv4_service_class_stats_db __percpu *stats_pcpu_psc;
+ /* Database to maintain per cpu per service class statistics */
struct sfe_ipv4_stats __percpu *stats_pcpu;
/* Per CPU statistics. */
@@ -394,6 +419,7 @@
int *total_read, struct sfe_ipv4_debug_xml_write_state *ws);
u16 sfe_ipv4_gen_ip_csum(struct iphdr *iph);
+void sfe_ipv4_service_class_stats_inc(struct sfe_ipv4 *si, uint8_t sid, uint64_t bytes);
void sfe_ipv4_exception_stats_inc(struct sfe_ipv4 *si, enum sfe_ipv4_exception_events reason);
bool sfe_ipv4_remove_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c);
void sfe_ipv4_flush_connection(struct sfe_ipv4 *si, struct sfe_ipv4_connection *c, sfe_sync_reason_t reason);
diff --git a/sfe_ipv4_tcp.c b/sfe_ipv4_tcp.c
index 14283ea..fdb73e3 100644
--- a/sfe_ipv4_tcp.c
+++ b/sfe_ipv4_tcp.c
@@ -127,6 +127,7 @@
struct sfe_ipv4_connection_match *counter_cm;
u8 ttl;
u32 flags;
+ u32 service_class_id;
struct net_device *xmit_dev;
bool ret;
bool hw_csum;
@@ -695,6 +696,13 @@
*/
if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_MARK)) {
skb->mark = cm->mark;
+ /*
+ * Update service class stats if SAWF is valid.
+ */
+ if (likely(cm->sawf_valid)) {
+ service_class_id = SFE_GET_SAWF_SERVICE_CLASS(cm->mark);
+ sfe_ipv4_service_class_stats_inc(si, service_class_id, len);
+ }
}
/*
diff --git a/sfe_ipv4_udp.c b/sfe_ipv4_udp.c
index 61ed28e..abaa873 100644
--- a/sfe_ipv4_udp.c
+++ b/sfe_ipv4_udp.c
@@ -127,6 +127,7 @@
__be16 dest_port;
struct sfe_ipv4_connection_match *cm;
u8 ttl;
+ u32 service_class_id;
struct net_device *xmit_dev;
bool hw_csum;
int err;
@@ -538,6 +539,13 @@
*/
if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_MARK)) {
skb->mark = cm->mark;
+ /*
+ * Update service class stats if SAWF is valid.
+ */
+ if (likely(cm->sawf_valid)) {
+ service_class_id = SFE_GET_SAWF_SERVICE_CLASS(cm->mark);
+ sfe_ipv4_service_class_stats_inc(si, service_class_id, len);
+ }
}
/*
diff --git a/sfe_ipv6.c b/sfe_ipv6.c
index 162a1d7..0549bf4 100644
--- a/sfe_ipv6.c
+++ b/sfe_ipv6.c
@@ -31,6 +31,7 @@
#include <linux/netfilter.h>
#include <linux/inetdevice.h>
#include <linux/netfilter_ipv6.h>
+#include <linux/seqlock.h>
#include <net/protocol.h>
#include <net/addrconf.h>
#include <net/gre.h>
@@ -750,7 +751,22 @@
call_rcu(&c->rcu, sfe_ipv6_free_sfe_ipv6_connection_rcu);
}
- /*
+/*
+ * sfe_ipv6_service_class_stats_inc()
+ * Increment per cpu per service class stats.
+ */
+void sfe_ipv6_service_class_stats_inc(struct sfe_ipv6 *si, uint8_t sid, uint64_t bytes)
+{
+ struct sfe_ipv6_service_class_stats_db *sc_stats_db = this_cpu_ptr(si->stats_pcpu_psc);
+ struct sfe_ipv6_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_ipv6_exception_stats_inc()
* Increment exception stats.
*/
@@ -1063,6 +1079,8 @@
s32 flow_interface_num = msg->conn_rule.flow_top_interface_num;
s32 return_interface_num = msg->conn_rule.return_top_interface_num;
+ 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;
@@ -1228,6 +1246,16 @@
original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_FAST_XMIT_DEV_ADMISSION;
}
+ /*
+ * Mark SAWF metadata if the sawf tag is valid.
+ */
+ 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->sawf_valid = true;
+ original_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_MARK;
+ }
/*
* Add VLAN rule to original_cm
@@ -1413,6 +1441,17 @@
}
/*
+ * Mark return SAWF metadata 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->sawf_valid = true;
+ reply_cm->flags |= SFE_IPV6_CONNECTION_MATCH_FLAG_MARK;
+ }
+
+ /*
* Setup UDP Socket if found to be valid for decap.
*/
RCU_INIT_POINTER(reply_cm->up, NULL);
@@ -1966,6 +2005,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];
@@ -2026,6 +2068,13 @@
ether_addr_copy(pppoe_remote_mac, original_cm->pppoe_remote_mac);
dest_mark = reply_cm->mark;
reply_fast_xmit = reply_cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_FAST_XMIT;
+ 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;
@@ -2077,6 +2126,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)) {
@@ -2533,12 +2592,22 @@
}
/*
+ * Allocate per cpu per service class memory.
+ */
+ si->stats_pcpu_psc = alloc_percpu_gfp(struct sfe_ipv6_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_ipv6
*/
si->sys_ipv6 = kobject_create_and_add("sfe_ipv6", NULL);
if (!si->sys_ipv6) {
DEBUG_ERROR("failed to register sfe_ipv6\n");
- goto exit1;
+ goto exit2;
}
/*
@@ -2547,20 +2616,20 @@
result = sysfs_create_file(si->sys_ipv6, &sfe_ipv6_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_ipv6, &sfe_ipv6_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_ipv6, &sfe_ipv6_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 */
@@ -2573,7 +2642,7 @@
#endif
if (result < 0) {
DEBUG_ERROR("can't register nf local out hook: %d\n", result);
- goto exit5;
+ goto exit6;
} else {
DEBUG_ERROR("Register nf local out hook success: %d\n", result);
}
@@ -2584,7 +2653,7 @@
result = register_chrdev(0, "sfe_ipv6", &sfe_ipv6_debug_dev_fops);
if (result < 0) {
DEBUG_ERROR("Failed to register chrdev: %d\n", result);
- goto exit6;
+ goto exit7;
}
si->debug_dev = result;
@@ -2599,7 +2668,7 @@
return 0;
-exit6:
+exit7:
#ifdef SFE_PROCESS_LOCAL_OUT
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
DEBUG_TRACE("sfe: Unregister local out hook\n");
@@ -2610,20 +2679,23 @@
#endif
#endif
-exit5:
+exit6:
#ifdef CONFIG_NF_FLOW_COOKIE
sysfs_remove_file(si->sys_ipv6, &sfe_ipv6_flow_cookie_attr.attr);
-exit4:
+exit5:
#endif /* CONFIG_NF_FLOW_COOKIE */
sysfs_remove_file(si->sys_ipv6, &sfe_ipv6_cpu_attr.attr);
-exit3:
+exit4:
sysfs_remove_file(si->sys_ipv6, &sfe_ipv6_debug_dev_attr.attr);
-exit2:
+exit3:
kobject_put(si->sys_ipv6);
+exit2:
+ free_percpu(si->stats_pcpu_psc);
+
exit1:
free_percpu(si->stats_pcpu);
@@ -2650,6 +2722,7 @@
unregister_chrdev(si->debug_dev, "sfe_ipv6");
free_percpu(si->stats_pcpu);
+ free_percpu(si->stats_pcpu_psc);
#ifdef SFE_PROCESS_LOCAL_OUT
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
diff --git a/sfe_ipv6.h b/sfe_ipv6.h
index e478d5b..6022300 100644
--- a/sfe_ipv6.h
+++ b/sfe_ipv6.h
@@ -204,9 +204,11 @@
u16 l2_hdr_size;
/*
- * xmit device's feature
+ * xmit device's feature
*/
netdev_features_t features;
+
+ bool sawf_valid; /* Indicates mark has valid SAWF information. */
};
/*
@@ -343,6 +345,28 @@
};
/*
+ * sfe_ipv6_per_service_class_stats
+ * Per service class stats
+ */
+struct sfe_ipv6_per_service_class_stats {
+ u64 tx_bytes; /* Byte count */
+ u64 tx_packets; /* Packet count */
+ seqcount_t seq; /* seq lock for read/write protection */
+ /*
+ * TODO : Add the entries to be maintained later.
+ */
+};
+
+/*
+ * sfe_ipv6_service_class_stats_db
+ * Stat entries for each service class.
+ */
+struct sfe_ipv6_service_class_stats_db{
+ struct sfe_ipv6_per_service_class_stats psc_stats[SFE_MAX_SERVICE_CLASS_ID];
+ /* Per service class stats */
+};
+
+/*
* Per-module structure.
*/
struct sfe_ipv6 {
@@ -368,6 +392,8 @@
int flow_cookie_enable;
/* Enable/disable flow cookie at runtime */
#endif
+ struct sfe_ipv6_service_class_stats_db __percpu *stats_pcpu_psc;
+ /* Database to maintain per cpu per service class statistics */
struct sfe_ipv6_stats __percpu *stats_pcpu;
/* Common SFE counters. */
@@ -437,7 +463,7 @@
}
void sfe_ipv6_exception_stats_inc(struct sfe_ipv6 *si, enum sfe_ipv6_exception_events reason);
-
+void sfe_ipv6_service_class_stats_inc(struct sfe_ipv6 *si, uint8_t sid, uint64_t bytes);
struct sfe_ipv6_connection_match *
sfe_ipv6_find_connection_match_rcu(struct sfe_ipv6 *si, struct net_device *dev, u8 protocol,
struct sfe_ipv6_addr *src_ip, __be16 src_port,
diff --git a/sfe_ipv6_tcp.c b/sfe_ipv6_tcp.c
index 1f377a2..6f740d8 100644
--- a/sfe_ipv6_tcp.c
+++ b/sfe_ipv6_tcp.c
@@ -126,6 +126,7 @@
struct sfe_ipv6_connection_match *cm;
struct sfe_ipv6_connection_match *counter_cm;
u32 flags;
+ u32 service_class_id;
struct net_device *xmit_dev;
bool ret;
bool hw_csum;
@@ -697,6 +698,13 @@
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_MARK)) {
skb->mark = cm->mark;
+ /*
+ * Update service class stats if SAWF is valid.
+ */
+ if (likely(cm->sawf_valid)) {
+ service_class_id = SFE_GET_SAWF_SERVICE_CLASS(cm->mark);
+ sfe_ipv6_service_class_stats_inc(si, service_class_id, len);
+ }
}
/*
diff --git a/sfe_ipv6_udp.c b/sfe_ipv6_udp.c
index 3df6d51..08263bd 100644
--- a/sfe_ipv6_udp.c
+++ b/sfe_ipv6_udp.c
@@ -132,6 +132,7 @@
struct sfe_ipv6_addr *dest_ip;
__be16 src_port;
__be16 dest_port;
+ u32 service_class_id;
struct sfe_ipv6_connection_match *cm;
struct net_device *xmit_dev;
int ret;
@@ -529,6 +530,13 @@
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_MARK)) {
skb->mark = cm->mark;
+ /*
+ * Update service class stats if SAWF is valid.
+ */
+ if (likely(cm->sawf_valid)) {
+ service_class_id = SFE_GET_SAWF_SERVICE_CLASS(cm->mark);
+ sfe_ipv6_service_class_stats_inc(si, service_class_id, len);
+ }
}
/*