[qca-nss-clients] Added multitunnel support
Added multitunnel support in ipsecmgr module.
Change-Id: I9b7d32500196eab72dfc33a90f336482914a4abc
Signed-off-by: mandrw <mandrw@codeaurora.org>
diff --git a/ipsecmgr/nss_ipsecmgr.c b/ipsecmgr/nss_ipsecmgr.c
index 365bac3..21f758c 100644
--- a/ipsecmgr/nss_ipsecmgr.c
+++ b/ipsecmgr/nss_ipsecmgr.c
@@ -30,6 +30,8 @@
#include <asm/atomic.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
+#include <net/route.h>
+#include <net/ip6_route.h>
#include <nss_api_if.h>
#include <nss_ipsec.h>
@@ -40,7 +42,7 @@
extern bool nss_cmn_get_nss_enabled(void);
-static struct nss_ipsecmgr_drv ipsecmgr_ctx = {0};
+struct nss_ipsecmgr_drv *ipsecmgr_ctx;
/*
**********************
@@ -229,7 +231,7 @@
* Check if skb is non-linear
*/
if (skb_is_nonlinear(skb)) {
- nss_ipsecmgr_error("%p: NSS IPSEC does not support fragments %p\n", priv->nss_ctx, skb);
+ nss_ipsecmgr_error("%s: NSS IPSEC does not support fragments %p\n", dev->name, skb);
goto fail;
}
@@ -237,7 +239,7 @@
* Check if skb is shared
*/
if (unlikely(skb_shared(skb))) {
- nss_ipsecmgr_error("%p: Shared skb is not supported: %p\n", priv->nss_ctx, skb);
+ nss_ipsecmgr_error("%s: Shared skb is not supported: %p\n", dev->name, skb);
goto fail;
}
@@ -245,7 +247,7 @@
* Check if packet is given starting from network header
*/
if (skb->data != skb_network_header(skb)) {
- nss_ipsecmgr_error("%p: 'Skb data is not starting from IP header", priv->nss_ctx);
+ nss_ipsecmgr_error("%s: 'Skb data is not starting from IP header\n", dev->name);
goto fail;
}
@@ -260,7 +262,7 @@
}
if (expand_skb && pskb_expand_head(skb, nhead, ntail, GFP_KERNEL)) {
- nss_ipsecmgr_error("%p: unable to expand buffer\n", priv->nss_ctx);
+ nss_ipsecmgr_error("%s: unable to expand buffer\n", dev->name);
goto fail;
}
@@ -362,25 +364,77 @@
}
/*
+ * nss_ipsecmgr_get_dev()
+ * Get the net_device associated with the packet.
+ */
+static struct net_device *nss_ipsecmgr_get_dev(struct sk_buff *skb)
+{
+ struct dst_entry *dst;
+ struct net_device *dev;
+ uint32_t ip_addr;
+ struct rtable *rt;
+ struct flowi6 fl6;
+
+ skb_reset_network_header(skb);
+
+ switch (ip_hdr(skb)->version) {
+ case IPVERSION:
+ ip_addr = ip_hdr(skb)->saddr;
+
+ rt = ip_route_output(&init_net, ip_addr, 0, 0, 0);
+ if (IS_ERR(rt)) {
+ return NULL;
+ }
+
+ dst = (struct dst_entry *)rt;
+ break;
+
+ case 6:
+ memset(&fl6, 0, sizeof(fl6));
+ memcpy(&fl6.daddr, &ipv6_hdr(skb)->saddr, sizeof(fl6.daddr));
+
+ dst = ip6_route_output(&init_net, NULL, &fl6);
+ if (IS_ERR(dst)) {
+ return NULL;
+ }
+ break;
+
+ default:
+ nss_ipsecmgr_warn("%p:could not get dev for the flow\n", skb);
+ return NULL;
+ }
+
+ dev = dst->dev;
+ dst_release(dst);
+
+ return dev;
+}
+
+/*
* nss_ipsecmgr_tunnel_rx()
* receive NSS exception packets
*/
-static void nss_ipsecmgr_tunnel_rx(struct net_device *dev, struct sk_buff *skb, __attribute((unused)) struct napi_struct *napi)
+static void nss_ipsecmgr_tunnel_rx(struct net_device *dummy, struct sk_buff *skb, __attribute((unused)) struct napi_struct *napi)
{
struct nss_ipsecmgr_priv *priv;
nss_ipsecmgr_data_cb_t cb_fn;
+ struct net_device *dev;
uint16_t next_protocol;
void *cb_ctx;
- BUG_ON(dev == NULL);
+ BUG_ON(dummy == NULL);
BUG_ON(skb == NULL);
+ dev = nss_ipsecmgr_get_dev(skb);
+ if (unlikely(!dev)) {
+ nss_ipsecmgr_error("didn't find an tunnel dev\n");
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
/* hold the device till we process it */
dev_hold(dev);
- /*
- * XXX:need to ensure that the dev being accessed is not deleted
- */
priv = netdev_priv(dev);
skb->dev = dev;
@@ -392,7 +446,7 @@
* if tunnel creator gave a callback then send the packet without
* any modifications to him
*/
- if (cb_fn && cb_ctx) {
+ if (cb_fn) {
cb_fn(cb_ctx, skb);
goto done;
}
@@ -411,7 +465,7 @@
break;
default:
- nss_ipsecmgr_error("%p: Unsupported IP Version\n", priv->nss_ctx);
+ nss_ipsecmgr_error("%s: Unsupported IP Version\n", dev->name);
dev_kfree_skb_any(skb);
goto done;
}
@@ -443,9 +497,8 @@
* nss_ipsecmgr_tunnel_notify()
* asynchronous event reception
*/
-static void nss_ipsecmgr_tunnel_notify(void *app_data, struct nss_ipsec_msg *nim)
+static void nss_ipsecmgr_tunnel_notify(__attribute((unused))void *app_data, struct nss_ipsec_msg *nim)
{
- struct net_device *tun_dev = (struct net_device *)app_data;
struct nss_ipsecmgr_sa_stats *sa_stats;
struct nss_ipsec_node_stats *drv_stats;
struct nss_ipsecmgr_event stats_event;
@@ -456,7 +509,6 @@
struct nss_ipsecmgr_key key;
struct net_device *dev;
- BUG_ON(tun_dev == NULL);
BUG_ON(nim == NULL);
/*
@@ -478,12 +530,12 @@
*/
nss_ipsecmgr_sa_sel2key(&nim->msg.sa_stats.sel, &key);
- write_lock(&priv->lock);
+ write_lock(&ipsecmgr_ctx->lock);
- ref = nss_ipsecmgr_sa_lookup(priv, &key);
+ ref = nss_ipsecmgr_sa_lookup(&key);
if (!ref) {
- write_unlock(&priv->lock);
- nss_ipsecmgr_info("event received on deallocated SA tunnel:(%d)\n", nim->tunnel_id);
+ write_unlock(&ipsecmgr_ctx->lock);
+ nss_ipsecmgr_error("event received on deallocated SA tunnel:(%d)\n", nim->tunnel_id);
goto done;
}
@@ -498,7 +550,7 @@
memcpy(&sa_stats->sa, &sa->sa_info, sizeof(struct nss_ipsecmgr_sa));
sa_stats->crypto_index = sa->nim.msg.push.data.crypto_index;
- write_unlock(&priv->lock);
+ write_unlock(&ipsecmgr_ctx->lock);
/*
* if event callback is available then post the statistics using the callback function
@@ -521,9 +573,9 @@
case NSS_IPSEC_MSG_TYPE_SYNC_NODE_STATS:
- drv_stats = &ipsecmgr_ctx.enc_stats;
+ drv_stats = &ipsecmgr_ctx->enc_stats;
if (unlikely(nim->cm.interface == NSS_IPSEC_DECAP_IF_NUMBER)) {
- drv_stats = &ipsecmgr_ctx.dec_stats;
+ drv_stats = &ipsecmgr_ctx->dec_stats;
}
memcpy(drv_stats, &nim->msg.node_stats, sizeof(struct nss_ipsec_node_stats));
@@ -542,22 +594,24 @@
*/
static ssize_t nss_ipsecmgr_node_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
- char *local;
+ struct nss_ipsec_node_stats *enc_stats = &ipsecmgr_ctx->enc_stats;
+ struct nss_ipsec_node_stats *dec_stats = &ipsecmgr_ctx->dec_stats;
ssize_t ret = 0;
+ char *local;
int len;
local = vmalloc(NSS_IPSECMGR_MAX_BUF_SZ);
len = 0;
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_enqueued: %d\n", ipsecmgr_ctx.enc_stats.enqueued);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_completed: %d\n", ipsecmgr_ctx.enc_stats.completed);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_exceptioned: %d\n", ipsecmgr_ctx.enc_stats.exceptioned);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_enqueue_failed: %d\n", ipsecmgr_ctx.enc_stats.fail_enqueue);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_enqueued: %d\n", enc_stats->enqueued);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_completed: %d\n", enc_stats->completed);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_exceptioned: %d\n", enc_stats->exceptioned);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tencap_enqueue_failed: %d\n", enc_stats->fail_enqueue);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_enqueued: %d\n", ipsecmgr_ctx.dec_stats.enqueued);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_completed: %d\n", ipsecmgr_ctx.dec_stats.completed);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_exceptioned: %d\n", ipsecmgr_ctx.dec_stats.exceptioned);
- len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_enqueue_failed: %d\n", ipsecmgr_ctx.dec_stats.fail_enqueue);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_enqueued: %d\n", dec_stats->enqueued);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_completed: %d\n", dec_stats->completed);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_exceptioned: %d\n", dec_stats->exceptioned);
+ len += snprintf(local + len, NSS_IPSECMGR_MAX_BUF_SZ - len, "\tdecap_enqueue_failed: %d\n", dec_stats->fail_enqueue);
ret = simple_read_from_buffer(ubuf, sz, ppos, local, len + 1);
@@ -597,31 +651,13 @@
priv->cb_ctx = cb->ctx;
priv->data_cb = cb->data_fn;
priv->event_cb = cb->event_fn;
- priv->nss_ctx = nss_ipsec_get_context();
- priv->nss_ifnum = nss_ipsec_get_interface(priv->nss_ctx);
- if (priv->nss_ifnum < 0) {
- nss_ipsecmgr_error("Invalid nss interface :%d\n", priv->nss_ifnum);
- goto fail;
- }
-
- rwlock_init(&priv->lock);
- nss_ipsecmgr_init_sa_db(&priv->sa_db);
- nss_ipsecmgr_init_netmask_db(&priv->net_db);
- nss_ipsecmgr_init_flow_db(&priv->flow_db);
status = rtnl_is_locked() ? register_netdevice(dev) : register_netdev(dev);
if (status < 0) {
- nss_ipsecmgr_error("register net dev failed :%d\n", priv->nss_ifnum);
+ nss_ipsecmgr_error("register net dev failed :%s\n", dev->name);
goto fail;
}
- nss_ipsec_data_register(priv->nss_ifnum, nss_ipsecmgr_tunnel_rx, dev, 0);
- nss_ipsec_notify_register(NSS_IPSEC_ENCAP_IF_NUMBER, nss_ipsecmgr_tunnel_notify, dev);
- nss_ipsec_notify_register(NSS_IPSEC_DECAP_IF_NUMBER, nss_ipsecmgr_tunnel_notify, dev);
-
- priv->dentry = debugfs_create_dir(dev->name, ipsecmgr_ctx.dentry);
- init_completion(&priv->complete);
-
return dev;
fail:
free_netdev(dev);
@@ -638,24 +674,12 @@
{
struct nss_ipsecmgr_priv *priv = netdev_priv(dev);
- /*
- * Unregister the callbacks from the HLOS as we are no longer
- * interested in exception data & async messages
- */
- nss_ipsec_data_unregister(priv->nss_ctx, priv->nss_ifnum);
-
- nss_ipsec_notify_unregister(priv->nss_ctx, NSS_IPSEC_ENCAP_IF_NUMBER);
- nss_ipsec_notify_unregister(priv->nss_ctx, NSS_IPSEC_DECAP_IF_NUMBER);
priv->data_cb = NULL;
priv->event_cb = NULL;
nss_ipsecmgr_sa_flush_all(priv);
- if (priv->dentry) {
- debugfs_remove_recursive(priv->dentry);
- }
-
/*
* The unregister should start here but the expectation is that the free would
* happen when the reference count goes down to '0'
@@ -666,25 +690,97 @@
}
EXPORT_SYMBOL(nss_ipsecmgr_tunnel_del);
+static const struct net_device_ops nss_ipsecmgr_ipsec_ndev_ops;
+
+/*
+ * nss_ipsecmgr_dummy_netdevice_setup()
+ * Setup function for dummy netdevice.
+ */
+static void nss_ipsecmgr_dummy_netdevice_setup(struct net_device *dev)
+{
+}
+
/*
* nss_ipsecmgr_init()
* module init
*/
static int __init nss_ipsecmgr_init(void)
{
+ int status;
+
if (!nss_cmn_get_nss_enabled()) {
nss_ipsecmgr_info_always("NSS is not enabled in this platform\n");
return 0;
}
+ ipsecmgr_ctx = vmalloc(sizeof(struct nss_ipsecmgr_drv));
+ if (!ipsecmgr_ctx) {
+ nss_ipsecmgr_info_always("Allocating ipsecmgr context failed\n");
+ return 0;
+ }
+
+ ipsecmgr_ctx->nss_ctx = nss_ipsec_get_context();
+ if (!ipsecmgr_ctx->nss_ctx) {
+ nss_ipsecmgr_info_always("Getting NSS Context failed\n");
+ goto free;
+ }
+
+ ipsecmgr_ctx->nss_ifnum = nss_ipsec_get_interface(ipsecmgr_ctx->nss_ctx);
+ if (ipsecmgr_ctx->nss_ifnum < 0) {
+ nss_ipsecmgr_info_always("%p: Invalid interface number %d\n", ipsecmgr_ctx->nss_ctx, ipsecmgr_ctx->nss_ifnum);
+ goto free;
+ }
+
+ ipsecmgr_ctx->ndev = alloc_netdev(0, NSS_IPSECMGR_TUN_NAME, nss_ipsecmgr_dummy_netdevice_setup);
+ if (!ipsecmgr_ctx->ndev) {
+ nss_ipsecmgr_info_always("Ipsec: Could not allocate ipsec net_device\n");
+ goto free;
+ }
+
+ ipsecmgr_ctx->ndev->netdev_ops = &nss_ipsecmgr_ipsec_ndev_ops;
+
+ status = rtnl_is_locked() ? register_netdevice(ipsecmgr_ctx->ndev) : register_netdev(ipsecmgr_ctx->ndev);
+ if (status) {
+ nss_ipsecmgr_info_always("IPsec: Could not register ipsec net_device\n");
+ goto netdev_free;
+ }
+
+ rwlock_init(&ipsecmgr_ctx->lock);
+ nss_ipsecmgr_init_sa_db(&ipsecmgr_ctx->sa_db);
+ nss_ipsecmgr_init_netmask_db(&ipsecmgr_ctx->net_db);
+ nss_ipsecmgr_init_flow_db(&ipsecmgr_ctx->flow_db);
+
+
+ nss_ipsec_data_register(ipsecmgr_ctx->nss_ifnum, nss_ipsecmgr_tunnel_rx, ipsecmgr_ctx->ndev, 0);
+ nss_ipsec_notify_register(NSS_IPSEC_ENCAP_IF_NUMBER, nss_ipsecmgr_tunnel_notify, NULL);
+ nss_ipsec_notify_register(NSS_IPSEC_DECAP_IF_NUMBER, nss_ipsecmgr_tunnel_notify, NULL);
+
/*
* initialize debugfs.
*/
- ipsecmgr_ctx.dentry = debugfs_create_dir("qca-nss-ipsecmgr", NULL);
- debugfs_create_file("stats", S_IRUGO, ipsecmgr_ctx.dentry, NULL, &node_stats_op);
+ ipsecmgr_ctx->dentry = debugfs_create_dir("qca-nss-ipsecmgr", NULL);
+ if (!ipsecmgr_ctx->dentry) {
+ nss_ipsecmgr_info_always("Creating debug directory failed\n");
+ goto unregister_dev;
+
+ }
+
+ debugfs_create_file("stats", S_IRUGO, ipsecmgr_ctx->dentry, NULL, &node_stats_op);
nss_ipsecmgr_info_always("NSS IPsec manager loaded: %s\n", NSS_CLIENT_BUILD_ID);
return 0;
+
+unregister_dev:
+ rtnl_is_locked() ? unregister_netdevice(ipsecmgr_ctx->ndev) : unregister_netdev(ipsecmgr_ctx->ndev);
+
+netdev_free:
+ free_netdev(ipsecmgr_ctx->ndev);
+
+free:
+ vfree(ipsecmgr_ctx);
+ ipsecmgr_ctx = NULL;
+
+ return 0;
}
/*
@@ -693,15 +789,46 @@
*/
static void __exit nss_ipsecmgr_exit(void)
{
- nss_ipsecmgr_info_always("NSS IPsec manager unloaded\n");
+ if (!ipsecmgr_ctx) {
+ nss_ipsecmgr_info_always("Invalid ipsecmgr Context\n");
+ return;
+ }
+
+ if (!ipsecmgr_ctx->nss_ctx) {
+ nss_ipsecmgr_info_always("Invalid NSS Context\n");
+ vfree(ipsecmgr_ctx);
+ ipsecmgr_ctx = NULL;
+ return;
+ }
/*
- * cleanup debugfs.
+ * Unregister the callbacks from the HLOS as we are no longer
+ * interested in exception data & async messages
*/
- if (ipsecmgr_ctx.dentry) {
- debugfs_remove_recursive(ipsecmgr_ctx.dentry);
+ nss_ipsec_data_unregister(ipsecmgr_ctx->nss_ctx, ipsecmgr_ctx->nss_ifnum);
+
+ nss_ipsec_notify_unregister(ipsecmgr_ctx->nss_ctx, NSS_IPSEC_ENCAP_IF_NUMBER);
+ nss_ipsec_notify_unregister(ipsecmgr_ctx->nss_ctx, NSS_IPSEC_DECAP_IF_NUMBER);
+
+ if (ipsecmgr_ctx->ndev) {
+ rtnl_is_locked() ? unregister_netdevice(ipsecmgr_ctx->ndev) : unregister_netdev(ipsecmgr_ctx->ndev);
}
+ /*
+ * Remove debugfs directory and entries below that.
+ */
+ if (ipsecmgr_ctx->dentry) {
+ debugfs_remove_recursive(ipsecmgr_ctx->dentry);
+ }
+
+ /*
+ * Free the ipsecmgr ctx
+ */
+ vfree(ipsecmgr_ctx);
+ ipsecmgr_ctx = NULL;
+
+ nss_ipsecmgr_info_always("NSS IPsec manager unloaded\n");
+
}
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/ipsecmgr/nss_ipsecmgr_flow.c b/ipsecmgr/nss_ipsecmgr_flow.c
index 6d01acd..a6f8686 100644
--- a/ipsecmgr/nss_ipsecmgr_flow.c
+++ b/ipsecmgr/nss_ipsecmgr_flow.c
@@ -33,6 +33,8 @@
#include "nss_ipsecmgr_priv.h"
+extern struct nss_ipsecmgr_drv *ipsecmgr_ctx;
+
/*
*
* nss_ipsecmgr_flow_resp()
@@ -80,7 +82,7 @@
*/
nss_ipsecmgr_copy_nim(&flow->nim, &nss_nim);
- if (nss_ipsec_tx_msg(priv->nss_ctx, &nss_nim) != NSS_TX_SUCCESS) {
+ if (nss_ipsec_tx_msg(ipsecmgr_ctx->nss_ctx, &nss_nim) != NSS_TX_SUCCESS) {
/*
* XXX: Stop the TX queue and add this "entry"
* to pending queue
@@ -109,7 +111,7 @@
*/
nss_ipsecmgr_copy_nim(&flow->nim, &nss_nim);
- if (nss_ipsec_tx_msg(priv->nss_ctx, &nss_nim) != NSS_TX_SUCCESS) {
+ if (nss_ipsec_tx_msg(ipsecmgr_ctx->nss_ctx, &nss_nim) != NSS_TX_SUCCESS) {
/*
* XXX: add this "entry" to pending queue
*/
@@ -378,7 +380,7 @@
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_flow_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_flow_db *db = &priv->flow_db;
+ struct nss_ipsecmgr_flow_db *db = &ipsecmgr_ctx->flow_db;
struct nss_ipsecmgr_flow_entry *entry;
struct list_head *head;
int idx;
@@ -426,7 +428,7 @@
/*
* add flow to the database
*/
- db = &priv->flow_db;
+ db = &ipsecmgr_ctx->flow_db;
INIT_LIST_HEAD(&flow->node);
/*
@@ -468,9 +470,9 @@
/*
* flow lookup is done with read lock
*/
- read_lock_bh(&priv->lock);
+ read_lock_bh(&ipsecmgr_ctx->lock);
flow_ref = nss_ipsecmgr_flow_lookup(priv, &flow_key);
- read_unlock_bh(&priv->lock);
+ read_unlock_bh(&ipsecmgr_ctx->lock);
/*
* if flow is found then proceed with the TX
@@ -488,11 +490,11 @@
/*
* write lock as it can update the flow database
*/
- write_lock_bh(&priv->lock);
+ write_lock_bh(&ipsecmgr_ctx->lock);
subnet_ref = nss_ipsecmgr_v4_subnet_match(priv, &subnet_key);
if (!subnet_ref) {
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
return false;
}
@@ -509,7 +511,7 @@
flow_ref = nss_ipsecmgr_flow_alloc(priv, &flow_key);
if (!flow_ref) {
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
return false;
}
@@ -519,7 +521,7 @@
nss_ipsecmgr_ref_add(flow_ref, subnet_ref);
nss_ipsecmgr_ref_update(priv, flow_ref, &nim);
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
break;
@@ -532,9 +534,9 @@
/*
* flow lookup is done with read lock
*/
- read_lock_bh(&priv->lock);
+ read_lock_bh(&ipsecmgr_ctx->lock);
flow_ref = nss_ipsecmgr_flow_lookup(priv, &flow_key);
- read_unlock_bh(&priv->lock);
+ read_unlock_bh(&ipsecmgr_ctx->lock);
/*
* if flow is found then proceed with the TX
@@ -553,11 +555,11 @@
/*
* write lock as it can update the flow database
*/
- write_lock(&priv->lock);
+ write_lock(&ipsecmgr_ctx->lock);
subnet_ref = nss_ipsecmgr_v6_subnet_match(priv, &subnet_key);
if (!subnet_ref) {
- write_unlock(&priv->lock);
+ write_unlock(&ipsecmgr_ctx->lock);
return false;
}
@@ -573,7 +575,7 @@
*/
flow_ref = nss_ipsecmgr_flow_alloc(priv, &flow_key);
if (!flow_ref) {
- write_unlock(&priv->lock);
+ write_unlock(&ipsecmgr_ctx->lock);
return false;
}
@@ -583,7 +585,7 @@
nss_ipsecmgr_ref_add(flow_ref, subnet_ref);
nss_ipsecmgr_ref_update(priv, flow_ref, &nim);
- write_unlock(&priv->lock);
+ write_unlock(&ipsecmgr_ctx->lock);
break;
default:
diff --git a/ipsecmgr/nss_ipsecmgr_priv.h b/ipsecmgr/nss_ipsecmgr_priv.h
index 122382d..81d6e82 100644
--- a/ipsecmgr/nss_ipsecmgr_priv.h
+++ b/ipsecmgr/nss_ipsecmgr_priv.h
@@ -284,21 +284,11 @@
*/
struct nss_ipsecmgr_priv {
struct net_device *dev; /* back pointer to tunnel device */
- rwlock_t lock; /* lock for all DB operations */
-
- struct nss_ipsecmgr_sa_db sa_db; /* SA database */
- struct nss_ipsecmgr_netmask_db net_db; /* Subnet mask database */
- struct nss_ipsecmgr_flow_db flow_db; /* flow database */
void *cb_ctx; /* callback context */
nss_ipsecmgr_data_cb_t data_cb; /* data callback function */
nss_ipsecmgr_event_cb_t event_cb; /* event callback function */
- uint32_t nss_ifnum; /* NSS interface for sending data */
- struct nss_ctx_instance *nss_ctx; /* NSS context */
-
- struct dentry *dentry; /* Tunnel device debugfs entry */
- struct completion complete; /* completion for flow stats nss msg */
};
/*
@@ -306,6 +296,17 @@
*/
struct nss_ipsecmgr_drv {
struct dentry *dentry; /* Debugfs entry per ipsecmgr module */
+ struct net_device *ndev; /* IPsec dummy net device */
+
+ rwlock_t lock; /* lock for all DB operations */
+
+ struct nss_ipsecmgr_sa_db sa_db; /* SA database */
+ struct nss_ipsecmgr_netmask_db net_db; /* Subnet mask database */
+ struct nss_ipsecmgr_flow_db flow_db; /* flow database */
+
+ uint32_t nss_ifnum; /* NSS interface for sending data */
+
+ struct nss_ctx_instance *nss_ctx; /* NSS context */
struct nss_ipsec_node_stats enc_stats; /* Encap node stats */
struct nss_ipsec_node_stats dec_stats; /* Decap node stats */
@@ -1072,7 +1073,7 @@
* SA alloc/lookup/flush API(s)
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
-struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key);
+struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_lookup(struct nss_ipsecmgr_key *key);
void nss_ipsecmgr_sa_flush_all(struct nss_ipsecmgr_priv *priv);
#endif /* __NSS_IPSECMGR_PRIV_H */
diff --git a/ipsecmgr/nss_ipsecmgr_sa.c b/ipsecmgr/nss_ipsecmgr_sa.c
index 063ef12..f6d678e 100644
--- a/ipsecmgr/nss_ipsecmgr_sa.c
+++ b/ipsecmgr/nss_ipsecmgr_sa.c
@@ -32,6 +32,8 @@
#include "nss_ipsecmgr_priv.h"
+extern struct nss_ipsecmgr_drv *ipsecmgr_ctx;
+
/*
* SA operation info
*/
@@ -76,7 +78,7 @@
/*
* lock database
*/
- write_lock_bh(&priv->lock);
+ write_lock_bh(&ipsecmgr_ctx->lock);
/*
* search the flow for deletion
@@ -86,7 +88,7 @@
/*
* unlock device
*/
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
nss_ipsecmgr_warn("%p:failed to lookup child_entry\n", priv->dev);
nss_ipsecmgr_trace("%p:child_lookup(%p)\n", priv, info->child_lookup);
@@ -96,9 +98,9 @@
/*
* search the SA in sa_db
*/
- sa_ref = nss_ipsecmgr_sa_lookup(priv, &info->sa_key);
+ sa_ref = nss_ipsecmgr_sa_lookup(&info->sa_key);
if (!sa_ref) {
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
nss_ipsecmgr_warn("%p:failed to lookup sa_entry\n", priv->dev);
return false;
@@ -116,7 +118,7 @@
*/
nss_ipsecmgr_sa_free(priv, sa_ref);
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
return true;
}
@@ -135,7 +137,7 @@
/*
* lock database
*/
- write_lock_bh(&priv->lock);
+ write_lock_bh(&ipsecmgr_ctx->lock);
/*
* allocate a flow, this returns either a new flow or an existing
@@ -146,7 +148,7 @@
/*
* unlock device
*/
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
nss_ipsecmgr_warn("%p:failed to alloc child_entry\n", priv->dev);
nss_ipsecmgr_trace("%p:child_alloc(%p)\n", priv, info->child_alloc);
@@ -163,7 +165,7 @@
* release the flow and unlock device
*/
nss_ipsecmgr_ref_free(priv, child_ref);
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
nss_ipsecmgr_warn("%p:failed to alloc sa_entry\n", priv->dev);
return false;
@@ -195,7 +197,7 @@
*/
nss_ipsecmgr_ref_update(priv, child_ref, &info->nim);
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
return true;
}
@@ -213,7 +215,7 @@
/*
* Search the object in the database first
*/
- ref = nss_ipsecmgr_sa_lookup(priv, key);
+ ref = nss_ipsecmgr_sa_lookup(key);
if (ref) {
return ref;
}
@@ -236,7 +238,7 @@
* initialize sa list node
*/
ref = &sa->ref;
- db = &priv->sa_db;
+ db = &ipsecmgr_ctx->sa_db;
INIT_LIST_HEAD(&sa->node);
/*
@@ -425,9 +427,9 @@
* nss_ipsecmgr_sa_lookup()
* lookup the SA in the sa_db
*/
-struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
+struct nss_ipsecmgr_ref *nss_ipsecmgr_sa_lookup(struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_sa_db *db = &priv->sa_db;
+ struct nss_ipsecmgr_sa_db *db = &ipsecmgr_ctx->sa_db;
struct nss_ipsecmgr_sa_entry *entry;
struct list_head *head;
int idx;
@@ -450,8 +452,9 @@
*/
struct rtnl_link_stats64 *nss_ipsecmgr_sa_stats_all(struct nss_ipsecmgr_priv *priv, struct rtnl_link_stats64 *stats)
{
- struct nss_ipsecmgr_sa_db *sa_db = &priv->sa_db;
+ struct nss_ipsecmgr_sa_db *sa_db = &ipsecmgr_ctx->sa_db;
struct nss_ipsecmgr_sa_entry *sa;
+ int ifindex = priv->dev->ifindex;
struct list_head *head;
int i;
@@ -460,13 +463,18 @@
/*
* trigger a stats update chain
*/
- read_lock_bh(&priv->lock);
+ read_lock_bh(&ipsecmgr_ctx->lock);
/*
* walk the SA database for each entry and get stats for attached SA
*/
for (i = 0, head = sa_db->entries; i < NSS_IPSECMGR_MAX_SA; i++, head++) {
list_for_each_entry(sa, head, node) {
+
+ if (sa->nim.tunnel_id != ifindex) {
+ continue;
+ }
+
/*
* Check the SA type (ENCAP or DECAP)
*/
@@ -499,7 +507,7 @@
}
}
- read_unlock_bh(&priv->lock);
+ read_unlock_bh(&ipsecmgr_ctx->lock);
return stats;
}
@@ -510,30 +518,33 @@
*/
void nss_ipsecmgr_sa_flush_all(struct nss_ipsecmgr_priv *priv)
{
- struct nss_ipsecmgr_sa_db *sa_db = &priv->sa_db;
+ struct nss_ipsecmgr_sa_db *sa_db = &ipsecmgr_ctx->sa_db;
struct nss_ipsecmgr_sa_entry *entry;
+ int ifindex = priv->dev->ifindex;
struct list_head *head;
int i;
/*
* lock database
*/
- write_lock_bh(&priv->lock);
+ write_lock_bh(&ipsecmgr_ctx->lock);
/*
- * walk the SA database for each entry and delete the attached SA
+ * walk the SA database for each entry and delete the attached SA.
+ * Assumption is that single SA cannot be associated to multiple ipsectunX interfaces.
*/
for (i = 0, head = sa_db->entries; i < NSS_IPSECMGR_MAX_SA; i++, head++) {
- while (!list_empty(head)) {
- entry = list_first_entry(head, struct nss_ipsecmgr_sa_entry, node);
- nss_ipsecmgr_ref_free(priv, &entry->ref);
+ list_for_each_entry(entry, head, node) {
+ if (entry->nim.tunnel_id == ifindex) {
+ nss_ipsecmgr_ref_free(priv, &entry->ref);
+ }
}
}
/*
* unlock database
*/
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
}
/*
@@ -803,14 +814,14 @@
/*
* lock database
*/
- write_lock_bh(&priv->lock);
+ write_lock_bh(&ipsecmgr_ctx->lock);
/*
* search the SA in sa_db
*/
- sa_ref = nss_ipsecmgr_sa_lookup(priv, &sa_key);
+ sa_ref = nss_ipsecmgr_sa_lookup(&sa_key);
if (!sa_ref) {
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
nss_ipsecmgr_warn("%p:failed to lookup SA\n", priv);
return false;
}
@@ -823,7 +834,7 @@
/*
* unlock database
*/
- write_unlock_bh(&priv->lock);
+ write_unlock_bh(&ipsecmgr_ctx->lock);
return true;
}
diff --git a/ipsecmgr/nss_ipsecmgr_subnet.c b/ipsecmgr/nss_ipsecmgr_subnet.c
index a0d474a..4362b72 100644
--- a/ipsecmgr/nss_ipsecmgr_subnet.c
+++ b/ipsecmgr/nss_ipsecmgr_subnet.c
@@ -35,6 +35,8 @@
#include "nss_ipsecmgr_priv.h"
+extern struct nss_ipsecmgr_drv *ipsecmgr_ctx;
+
/*
* nss_ipsecmgr_subnet_key_data2idx()
* subnet specific api for converting word stream to index
@@ -185,7 +187,7 @@
*/
list_del(&subnet->node);
- nss_ipsecmgr_netmask_free(&priv->net_db, &subnet->key);
+ nss_ipsecmgr_netmask_free(&ipsecmgr_ctx->net_db, &subnet->key);
kfree(subnet);
}
@@ -195,7 +197,7 @@
*/
static inline struct nss_ipsecmgr_netmask_entry *nss_ipsecmgr_netmask_lookup(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_netmask_db *db = &priv->net_db;
+ struct nss_ipsecmgr_netmask_db *db = &ipsecmgr_ctx->net_db;
uint32_t idx;
if (nss_ipsecmgr_netmask_is_default(key)) {
@@ -212,7 +214,7 @@
*/
static struct nss_ipsecmgr_netmask_entry *nss_ipsecmgr_netmask_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_netmask_db *db = &priv->net_db;
+ struct nss_ipsecmgr_netmask_db *db = &ipsecmgr_ctx->net_db;
struct nss_ipsecmgr_netmask_entry *entry;
int idx;
@@ -356,7 +358,7 @@
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_v4_subnet_match(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_netmask_db *db = &priv->net_db;
+ struct nss_ipsecmgr_netmask_db *db = &ipsecmgr_ctx->net_db;
struct nss_ipsecmgr_key tmp_key;
struct nss_ipsecmgr_ref *ref;
int i;
@@ -404,7 +406,7 @@
*/
struct nss_ipsecmgr_ref *nss_ipsecmgr_v6_subnet_match(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key)
{
- struct nss_ipsecmgr_netmask_db *db = &priv->net_db;
+ struct nss_ipsecmgr_netmask_db *db = &ipsecmgr_ctx->net_db;
struct nss_ipsecmgr_key tmp_key;
struct nss_ipsecmgr_ref *ref;
int i;
@@ -502,7 +504,7 @@
*/
subnet = kzalloc(sizeof(struct nss_ipsecmgr_subnet_entry), GFP_ATOMIC);
if (!subnet) {
- nss_ipsecmgr_netmask_free(&priv->net_db, key);
+ nss_ipsecmgr_netmask_free(&ipsecmgr_ctx->net_db, key);
return NULL;
}
diff --git a/netlink/nss_nlipv4.c b/netlink/nss_nlipv4.c
index e30c508..dd2a268 100755
--- a/netlink/nss_nlipv4.c
+++ b/netlink/nss_nlipv4.c
@@ -301,10 +301,19 @@
}
/*
- * update flow and return interface numbers
+ * update flow and return interface numbers. Handle Ipsec interfaces seperately.
*/
- conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
- conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+ if (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC) {
+ conn->flow_interface_num = nss_ipsec_get_interface(nss_ipsec_get_context());
+ } else {
+ conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
+ }
+
+ if (return_dev->type == NSS_IPSEC_ARPHRD_IPSEC) {
+ conn->flow_interface_num = nss_ipsec_get_interface(nss_ipsec_get_context());
+ } else {
+ conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+ }
/*
* update the flow & return MTU(s)
diff --git a/netlink/nss_nlipv6.c b/netlink/nss_nlipv6.c
index 42a90d5..d59b2f9 100644
--- a/netlink/nss_nlipv6.c
+++ b/netlink/nss_nlipv6.c
@@ -302,10 +302,19 @@
}
/*
- * update flow and return interface numbers
+ * update flow and return interface numbers. Handle Ipsec interfaces seperately.
*/
- conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
- conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+ if (flow_dev->type == NSS_IPSEC_ARPHRD_IPSEC) {
+ conn->flow_interface_num = nss_ipsec_get_interface(nss_ipsec_get_context());
+ } else {
+ conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(flow_dev);
+ }
+
+ if (return_dev->type == NSS_IPSEC_ARPHRD_IPSEC) {
+ conn->flow_interface_num = nss_ipsec_get_interface(nss_ipsec_get_context());
+ } else {
+ conn->return_interface_num = nss_cmn_get_interface_number_by_dev(return_dev);
+ }
/*
* update the flow & return MTU(s)