Adding suppport for boot time #Conn cfg

Adding support using sysctl to configure the number of
connections supported by IPv4 and IPv6 in NSS FW. This
configuration is boot time configuration. Update file
/etc/sysctl.conf with the following entry (an example)
dev.nss.ipv4cfg.ipv4_conn=512
dev.nss.ipv6cfg.ipv6_conn=1024

Change-Id: Ifb3e655d330cd79048231fae60d27dbb9eb37856
Signed-off-by: Vijay Dewangan <vdewanga@codeaurora.org>
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index 6549a84..f6698e9 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -369,7 +369,6 @@
 #define NSS_IPV6_CREATE_FLAG_VLAN_MARKING 0x10
 					/** Rule for VLAN marking */
 
-
 /**
  * Structure to be used while sending an IPv6 flow/connection destroy rule.
  */
diff --git a/exports/nss_ipv4.h b/exports/nss_ipv4.h
index 24a7da4..595593a 100644
--- a/exports/nss_ipv4.h
+++ b/exports/nss_ipv4.h
@@ -36,6 +36,7 @@
 	NSS_IPV4_RX_ESTABLISH_RULE_MSG,		/**< IPv4 establish rule message */
 	NSS_IPV4_RX_CONN_STATS_SYNC_MSG,	/**< IPv4 connection stats sync message */
 	NSS_IPV4_RX_NODE_STATS_SYNC_MSG,	/**< IPv4 generic statistics sync message */
+	NSS_IPV4_TX_CONN_CFG_RULE_MSG,		/**< IPv4 number of connections supported rule message */
 	NSS_IPV4_MAX_MSG_TYPES,			/**< IPv4 message max type number */
 };
 
@@ -187,6 +188,14 @@
 };
 
 /**
+ * The IPv4 rule number of supported connections sub-message structure.
+ */
+struct nss_ipv4_rule_conn_cfg_msg {
+	uint32_t num_conn;	/**< Number of supported IPv4 connections */
+};
+
+
+/**
  * The NSS IPv4 rule establish structure.
  */
 struct nss_ipv4_rule_establish {
@@ -373,6 +382,7 @@
 		struct nss_ipv4_rule_establish rule_establish;	/**< Message: rule establish confirmation */
 		struct nss_ipv4_conn_sync conn_stats;	/**< Message: connection stats sync */
 		struct nss_ipv4_node_sync node_stats;	/**< Message: node stats sync */
+		struct nss_ipv4_rule_conn_cfg_msg rule_conn_cfg;	/**< Message: rule connections supported */
 	} msg;
 };
 
@@ -422,4 +432,18 @@
  */
 extern void nss_ipv4_register_handler(void);
 
+/**
+ * @brief IPv4 sysctl register
+ *
+ * @return None
+ */
+extern void nss_ipv4_register_sysctl(void);
+
+/**
+ * @brief IPv4 sysctl unregister
+ *
+ * @return None
+ */
+extern void nss_ipv4_unregister_sysctl(void);
+
 #endif /* __NSS_IPV4_H */
diff --git a/exports/nss_ipv6.h b/exports/nss_ipv6.h
index e08513a..7535e66 100644
--- a/exports/nss_ipv6.h
+++ b/exports/nss_ipv6.h
@@ -36,6 +36,7 @@
 	NSS_IPV6_RX_ESTABLISH_RULE_MSG,		/**< IPv6 establish rule message */
 	NSS_IPV6_RX_CONN_STATS_SYNC_MSG,	/**< IPv6 connection stats sync message */
 	NSS_IPV6_RX_NODE_STATS_SYNC_MSG,	/**< IPv6 generic statistics sync message */
+	NSS_IPV6_TX_CONN_CFG_RULE_MSG,		/**< IPv6 connection cfg rule message */
 	NSS_IPV6_MAX_MSG_TYPES,
 };
 
@@ -225,6 +226,13 @@
 };
 
 /**
+ * The IPv6 rule conn cfgsub-message structure.
+ */
+struct nss_ipv6_rule_conn_cfg_msg {
+	uint32_t num_conn;	/**< Holds number of supported connections in IPv6 */
+};
+
+/**
  * The NSS IPv6 rule establish structure.
  */
 struct nss_ipv6_rule_establish {
@@ -344,6 +352,7 @@
 		struct nss_ipv6_rule_establish rule_establish;	/**< Message: rule establish confirmation */
 		struct nss_ipv6_conn_sync conn_stats;		/**< Message: stats sync */
 		struct nss_ipv6_node_sync node_stats;		/**< Message: node stats sync */
+		struct nss_ipv6_rule_conn_cfg_msg rule_conn_cfg;/**< Message: rule conn cfg */
 	} msg;
 };
 
@@ -392,4 +401,20 @@
  * @return none
  */
 extern void nss_ipv6_register_handler(void);
+
+/**
+ * @brief IPv4 sysctl register
+ *
+ * @return None
+ */
+extern void nss_ipv6_register_sysctl(void);
+
+/**
+ * @brief IPv4 sysctl unregister
+ *
+ * @return None
+ */
+extern void nss_ipv6_unregister_sysctl(void);
+
+
 #endif /* __NSS_IPV6_H */
diff --git a/nss_hlos_if.h b/nss_hlos_if.h
index ec70158..1251ce8 100755
--- a/nss_hlos_if.h
+++ b/nss_hlos_if.h
@@ -22,6 +22,15 @@
 #ifndef __NSS_HLOS_IF_H
 #define __NSS_HLOS_IF_H
 
+#define MIN_NUM_CONN 			256	/**< MIN  Connection shared between IPv4 and IPv6 */
+#define MAX_TOTAL_NUM_CONN_IPV4_IPV6	8196	/**< MAX Connection shared between IPv4 and IPv6 */
+
+/*
+ * Variables used for sysctl updates.
+ */
+extern int nss_ipv4_conn_cfg;
+extern int nss_ipv6_conn_cfg;
+
 /*
  * Request/Response types
  */
diff --git a/nss_init.c b/nss_init.c
index 4d04bdd..646ab0d 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -829,30 +829,29 @@
 		.data                   = &nss_ctl_redirect,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = proc_dointvec,
+		.proc_handler   	= proc_dointvec,
 	},
 	{
 		.procname               = "debug",
 		.data                   = &nss_ctl_debug,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_debug_handler,
+		.proc_handler   	= &nss_debug_handler,
 	},
 	{
 		.procname               = "coredump",
 		.data                   = &nss_cmd_buf.coredump,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_coredump_handler,
+		.proc_handler   	= &nss_coredump_handler,
 	},
 	{
 		.procname               = "rps",
 		.data                   = &nss_rps_cfg,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_rpscfg_handler,
+		.proc_handler   	= &nss_rpscfg_handler,
 	},
-
 	{ }
 };
 
@@ -921,6 +920,12 @@
 	nss_dev_header = register_sysctl_table(nss_root);
 
 	/*
+	 * Registering sysctl for ipv4/6 specific config.
+	 */
+	nss_ipv4_register_sysctl();
+	nss_ipv6_register_sysctl();
+
+	/*
 	 * Setup Runtime Sample values
 	 */
 	nss_runtime_samples.freq_scale[0].frequency = 	NSS_FREQ_110;
@@ -980,6 +985,12 @@
 	if (nss_dev_header)
 		unregister_sysctl_table(nss_dev_header);
 
+	/*
+	 * Unregister ipv4/6 specific sysctl
+	 */
+	nss_ipv4_unregister_sysctl();
+	nss_ipv6_unregister_sysctl();
+
 	platform_driver_unregister(&nss_driver);
 }
 
diff --git a/nss_ipv4.c b/nss_ipv4.c
index 05bdea3..68d28b9 100644
--- a/nss_ipv4.c
+++ b/nss_ipv4.c
@@ -18,6 +18,7 @@
  * nss_ipv4.c
  *	NSS IPv4 APIs
  */
+#include <linux/sysctl.h>
 #include <linux/ppp_channel.h>
 #include "nss_tx_rx_common.h"
 
@@ -25,6 +26,8 @@
 extern void nss_rx_metadata_ipv4_create_response(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim);
 extern void nss_rx_ipv4_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync *nirs);
 
+int nss_ipv4_conn_cfg __read_mostly = 4096;
+
 /*
  * nss_ipv4_driver_conn_sync_update()
  *	Update driver specific information from the messsage.
@@ -300,7 +303,153 @@
 	}
 }
 
+/*
+ * nss_ipv4_conn_cfg_callback()
+ *	call back function for the ipv6 connection configuration handler
+ */
+static void nss_ipv4_conn_cfg_callback(void *app_data, struct nss_if_msg *nim)
+{
+
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("IPv4 connection configuration failed with error: %d\n", nim->cm.error);
+		return;
+	}
+
+	nss_info("IPv4 connection configuration success: %d\n", nim->cm.error);
+}
+
+/*
+ * nss_ipv4_conn_cfg_handler()
+ *	Sets the number of connections for IPv4
+ */
+static int nss_ipv4_conn_cfg_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
+	struct nss_ipv4_msg nim;
+	struct nss_ipv4_rule_conn_cfg_msg *nirccm;
+	nss_tx_status_t nss_tx_status;
+	int ret = 1;
+	uint32_t sum_of_conn = nss_ipv4_conn_cfg + nss_ipv6_conn_cfg;
+
+	/*
+	 * The input should be power of 2.
+	 * Input for ipv4 and ipv6 sum togther should not exceed 8k
+	 * Min. value should be at leat 256 connections. This is the
+	 * minimum connections we will support for each of them.
+	 */
+	if ((nss_ipv4_conn_cfg & (nss_ipv4_conn_cfg - 1)) ||
+		(sum_of_conn > MAX_TOTAL_NUM_CONN_IPV4_IPV6) ||
+		(nss_ipv4_conn_cfg < MIN_NUM_CONN)) {
+		nss_warning("%p: input supported connections (%d) does not adhere\
+				specifications\n1) not power of 2,\n2) is less than \
+				min val: %d, OR\n 	IPv4/6 total exceeds %d\n",
+				nss_ctx,
+				nss_ipv4_conn_cfg,
+				MIN_NUM_CONN,
+				MAX_TOTAL_NUM_CONN_IPV4_IPV6);
+		return ret;
+	}
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+	if (ret) {
+		return ret;
+	}
+
+	if ((!write)) {
+		nss_warning("%p: IPv4 supported connections write failed: %d\n", nss_ctx, nss_ipv4_conn_cfg);
+		return ret;
+	}
+
+
+	nss_info("%p: IPv4 supported connections: %d\n", nss_ctx, nss_ipv4_conn_cfg);
+
+	nss_cmn_msg_init(&nim.cm, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CONN_CFG_RULE_MSG,
+	sizeof(struct nss_ipv4_rule_conn_cfg_msg), nss_ipv4_conn_cfg_callback, NULL);
+
+	nirccm = &nim.msg.rule_conn_cfg;
+	nirccm->num_conn = htonl(nss_ipv4_conn_cfg);
+	nss_tx_status = nss_ipv4_tx(nss_ctx, &nim);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx error setting IPv4 Connections: %d\n",
+							nss_ctx,
+							nss_ipv4_conn_cfg);
+	}
+	return ret;
+}
+
+static ctl_table nss_ipv4_table[] = {
+	{
+		.procname               = "ipv4_conn",
+		.data                   = &nss_ipv4_conn_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_ipv4_conn_cfg_handler,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv4_dir[] = {
+	{
+		.procname               = "ipv4cfg",
+		.mode                   = 0555,
+		.child                  = nss_ipv4_table,
+	},
+	{ }
+};
+
+
+static ctl_table nss_ipv4_root_dir[] = {
+	{
+		.procname		= "nss",
+		.mode			= 0555,
+		.child			= nss_ipv4_dir,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv4_root[] = {
+	{
+		.procname		= "dev",
+		.mode			= 0555,
+		.child			= nss_ipv4_root_dir,
+	},
+	{ }
+};
+
+static struct ctl_table_header *nss_ipv4_header;
+
+/*
+ * nss_ipv4_register_sysctl()
+ *	Register sysctl specific to ipv4
+ */
+void nss_ipv4_register_sysctl(void)
+{
+	/*
+	 * Register sysctl table.
+	 */
+	nss_ipv4_header = register_sysctl_table(nss_ipv4_root);
+}
+
+/*
+ * nss_ipv4_unregister_sysctl()
+ *	Unregister sysctl specific to ipv4
+ */
+void nss_ipv4_unregister_sysctl(void)
+{
+	/*
+	 * Unregister sysctl table.
+	 */
+	if (nss_ipv4_header) {
+		unregister_sysctl_table(nss_ipv4_header);
+	}
+}
+
 EXPORT_SYMBOL(nss_ipv4_tx);
 EXPORT_SYMBOL(nss_ipv4_notify_register);
 EXPORT_SYMBOL(nss_ipv4_notify_unregister);
 EXPORT_SYMBOL(nss_ipv4_get_mgr);
+EXPORT_SYMBOL(nss_ipv4_register_sysctl);
+EXPORT_SYMBOL(nss_ipv4_unregister_sysctl);
diff --git a/nss_ipv6.c b/nss_ipv6.c
index 94bfc81..3b51486 100644
--- a/nss_ipv6.c
+++ b/nss_ipv6.c
@@ -25,6 +25,8 @@
 extern void nss_rx_metadata_ipv6_create_response(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *nim);
 extern void nss_rx_ipv6_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_conn_sync *nirs);
 
+int nss_ipv6_conn_cfg __read_mostly = 4096;
+
 /*
  * nss_ipv6_driver_conn_sync_update()
  *	Update driver specific information from the messsage.
@@ -300,8 +302,153 @@
 	}
 }
 
+/*
+ * nss_ipv6_conn_cfg_callback()
+ *	call back function for the ipv6 connection configuration handler
+ */
+static void nss_ipv6_conn_cfg_callback(void *app_data, struct nss_if_msg *nim)
+{
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("IPv6 connection configuration failed with error: %d\n", nim->cm.error);
+		return;
+	}
+
+	nss_info("IPv6 connection configuration success: %d\n", nim->cm.error);
+}
+
+
+/*
+ * nss_ipv6_conn_cfg_handler()
+ *	Sets the number of connections for IPv6
+ */
+static int nss_ipv6_conn_cfg_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
+	struct nss_ipv6_msg nim;
+	struct nss_ipv6_rule_conn_cfg_msg *nirccm;
+	nss_tx_status_t nss_tx_status;
+	int ret = 1;
+	uint32_t sum_of_conn = nss_ipv4_conn_cfg + nss_ipv6_conn_cfg;
+
+	/*
+	 * Specifications for input
+	 * 1) The input should be power of 2.
+	 * 2) Input for ipv4 and ipv6 sum togther should not exceed 8k
+	 * 3) Min. value should be at leat 256 connections. This is the
+	 * minimum connections we will support for each of them.
+	 */
+	if ((nss_ipv6_conn_cfg & (nss_ipv6_conn_cfg - 1)) ||
+		(sum_of_conn > MAX_TOTAL_NUM_CONN_IPV4_IPV6) ||
+		(nss_ipv6_conn_cfg < MIN_NUM_CONN)) {
+		nss_warning("%p: input supported connections (%d) does not adhere\
+				specifications\n1) not power of 2,\n2) is less than \
+				min val: %d, OR\n 	IPv4/6 total exceeds %d\n",
+				nss_ctx,
+				nss_ipv6_conn_cfg,
+				MIN_NUM_CONN,
+				MAX_TOTAL_NUM_CONN_IPV4_IPV6);
+		return ret;
+	}
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+	if (ret) {
+		return ret;
+	}
+
+	if (!write) {
+		nss_warning("%p: IPv6 supported connections write failed: %d\n", nss_ctx, nss_ipv6_conn_cfg);
+		return ret;
+	}
+
+	nss_info("%p: IPv6 supported connections: %d\n", nss_ctx, nss_ipv6_conn_cfg);
+
+	nss_cmn_msg_init(&nim.cm, NSS_IPV6_RX_INTERFACE, NSS_IPV6_TX_CONN_CFG_RULE_MSG,
+		sizeof(struct nss_ipv6_rule_conn_cfg_msg), nss_ipv6_conn_cfg_callback, NULL);
+
+	nirccm = &nim.msg.rule_conn_cfg;
+	nirccm->num_conn = htonl(nss_ipv6_conn_cfg);
+	nss_tx_status = nss_ipv6_tx(nss_ctx, &nim);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx error setting IPv6 Connections: %d\n",
+						nss_ctx,
+						nss_ipv6_conn_cfg);
+	}
+	return ret;
+}
+
+static ctl_table nss_ipv6_table[] = {
+	{
+		.procname               = "ipv6_conn",
+		.data                   = &nss_ipv6_conn_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_ipv6_conn_cfg_handler,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_dir[] = {
+	{
+		.procname               = "ipv6cfg",
+		.mode                   = 0555,
+		.child                  = nss_ipv6_table,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_root_dir[] = {
+	{
+		.procname		= "nss",
+		.mode			= 0555,
+		.child			= nss_ipv6_dir,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_root[] = {
+	{
+		.procname		= "dev",
+		.mode			= 0555,
+		.child			= nss_ipv6_root_dir,
+	},
+	{ }
+};
+
+static struct ctl_table_header *nss_ipv6_header;
+
+/*
+ * nss_ipv6_register_sysctl()
+ *	Register sysctl specific to ipv4
+ */
+void nss_ipv6_register_sysctl(void)
+{
+	/*
+	 * Register sysctl table.
+	 */
+	nss_ipv6_header = register_sysctl_table(nss_ipv6_root);
+}
+
+/*
+ * nss_ipv6_unregister_sysctl()
+ *	Unregister sysctl specific to ipv4
+ */
+void nss_ipv6_unregister_sysctl(void)
+{
+	/*
+	 * Unregister sysctl table.
+	 */
+	if (nss_ipv6_header) {
+		unregister_sysctl_table(nss_ipv6_header);
+	}
+}
+
 EXPORT_SYMBOL(nss_ipv6_tx);
 EXPORT_SYMBOL(nss_ipv6_notify_register);
 EXPORT_SYMBOL(nss_ipv6_notify_unregister);
 EXPORT_SYMBOL(nss_ipv6_get_mgr);
 EXPORT_SYMBOL(nss_ipv6_register_handler);
+EXPORT_SYMBOL(nss_ipv6_register_sysctl);
+EXPORT_SYMBOL(nss_ipv6_unregister_sysctl);