mirror of
https://github.com/qosmio/nss-packages.git
synced 2025-12-17 08:42:18 +00:00
910 lines
29 KiB
Diff
910 lines
29 KiB
Diff
--- a/exports/nss_connmgr_tunipip6.h
|
|
+++ b/exports/nss_connmgr_tunipip6.h
|
|
@@ -28,12 +28,13 @@ enum nss_connmgr_tunipip6_err_codes {
|
|
NSS_CONNMGR_TUNIPIP6_TUN_DESTROY_FAILURE, /**< Tunnel destroy failure. */
|
|
NSS_CONNMGR_TUNIPIP6_TUN_NONE, /**< Invalid tunnel type */
|
|
NSS_CONNMGR_TUNIPIP6_NETDEV_TYPE_FAILURE, /**< Netdevice is not of type ipv6-in-ipv4. */
|
|
- NSS_CONNMGR_TUNIPIP6_MAPRULE_ADD_FAILURE, /**< BMR/FMR addition failure. */
|
|
- NSS_CONNMGR_TUNIPIP6_MAPRULE_DEL_FAILURE, /**< BMR/FMR deletion failure. */
|
|
- NSS_CONNMGR_TUNIPIP6_FMR_RULE_FLUSH_FAILURE, /**< FMR flush failure. */
|
|
+ NSS_CONNMGR_TUNIPIP6_MAPRULE_ADD_FAILURE, /**< BMR/FMR addition failure. */
|
|
+ NSS_CONNMGR_TUNIPIP6_MAPRULE_DEL_FAILURE, /**< BMR/FMR deletion failure. */
|
|
+ NSS_CONNMGR_TUNIPIP6_FMR_RULE_FLUSH_FAILURE, /**< FMR flush failure. */
|
|
NSS_CONNMGR_TUNIPIP6_NO_DEV, /**< No NSS node found. */
|
|
NSS_CONNMGR_TUNIPIP6_INVALID_PARAM, /**< Invalid tunnel parameters. */
|
|
NSS_CONNMGR_TUNIPIP6_INVALID_RULE_TYPE, /**< Invalid maprule type. */
|
|
+ NSS_CONNMGR_TUNIPIP6_CONTEXT_FAILURE, /**< Tunnel host context not found. */
|
|
};
|
|
|
|
/*
|
|
--- a/tunipip6/Makefile
|
|
+++ b/tunipip6/Makefile
|
|
@@ -2,9 +2,8 @@
|
|
ccflags-y += -I$(obj)/../exports -I$(obj)/..
|
|
ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)"
|
|
ccflags-y += -DNSS_TUNIPIP6_DEBUG_LEVEL=0
|
|
-ccflags-y += -Werror
|
|
obj-m += qca-nss-tunipip6.o
|
|
-qca-nss-tunipip6-objs := nss_connmgr_tunipip6.o nss_connmgr_tunipip6_sysctl.o
|
|
+qca-nss-tunipip6-objs := nss_connmgr_tunipip6.o nss_connmgr_tunipip6_sysctl.o nss_connmgr_tunipip6_stats.o
|
|
ifneq ($(findstring 4.4, $(KERNELVERSION)),)
|
|
ccflags-y += -DDRAFT03_SUPPORT
|
|
endif
|
|
--- a/tunipip6/nss_connmgr_tunipip6.c
|
|
+++ b/tunipip6/nss_connmgr_tunipip6.c
|
|
@@ -20,7 +20,6 @@
|
|
#include <linux/types.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/of.h>
|
|
-#include <linux/tcp.h>
|
|
#include <linux/module.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
@@ -29,71 +28,123 @@
|
|
#include <linux/if.h>
|
|
#include <net/ip_tunnels.h>
|
|
#include <net/ip6_tunnel.h>
|
|
-#include <linux/if_arp.h>
|
|
#include <nss_api_if.h>
|
|
#include "nss_connmgr_tunipip6.h"
|
|
#include "nss_connmgr_tunipip6_sysctl.h"
|
|
+#include "nss_connmgr_tunipip6_priv.h"
|
|
+
|
|
+#define NSS_TUNIPIP6_MAX_FMR 255 /* Maximum number of forward mapping rule (FMR). */
|
|
|
|
/*
|
|
- * NSS tunipip6 debug macros
|
|
+ * Frag Id update is disabled by default
|
|
*/
|
|
-#if (NSS_TUNIPIP6_DEBUG_LEVEL < 1)
|
|
-#define nss_tunipip6_assert(fmt, args...)
|
|
-#else
|
|
-#define nss_tunipip6_assert(c) if (!(c)) { BUG_ON(!(c)); }
|
|
-#endif
|
|
-
|
|
-#if defined(CONFIG_DYNAMIC_DEBUG)
|
|
+bool frag_id_update = false;
|
|
+/*
|
|
+ * Creating custom ipip6 interface is disabled by default.
|
|
+ */
|
|
+static bool enable_custom;
|
|
+module_param(enable_custom, bool, 0);
|
|
|
|
/*
|
|
- * Compile messages for dynamic enable/disable
|
|
+ * tunipip6 global context.
|
|
*/
|
|
-#define nss_tunipip6_warning(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#define nss_tunipip6_info(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#define nss_tunipip6_trace(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#else
|
|
+struct nss_tunipip6_context tunipip6_ctx;
|
|
|
|
/*
|
|
- * Statically compile messages at different levels
|
|
+ * nss_tunipip6_alloc_instance()
|
|
+ * Allocate tunipip6 interface instance.
|
|
*/
|
|
-#if (NSS_TUNIPIP6_DEBUG_LEVEL < 2)
|
|
-#define nss_tunipip6_warning(s, ...)
|
|
-#else
|
|
-#define nss_tunipip6_warning(s, ...) pr_warn("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#endif
|
|
+static struct nss_tunipip6_instance *nss_tunipip6_alloc_instance(struct net_device *dev,
|
|
+ int inner_ifnum,
|
|
+ int outer_ifnum)
|
|
+{
|
|
+ struct nss_tunipip6_instance*ntii;
|
|
|
|
-#if (NSS_TUNIPIP6_DEBUG_LEVEL < 3)
|
|
-#define nss_tunipip6_info(s, ...)
|
|
-#else
|
|
-#define nss_tunipip6_info(s, ...) pr_notice("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#endif
|
|
+ ntii = vzalloc(sizeof(*ntii));
|
|
+ if (!ntii) {
|
|
+ nss_tunipip6_warning("%px: Not able to allocate tunipip6 instance\n", dev);
|
|
+ return NULL;
|
|
+ }
|
|
|
|
-#if (NSS_TUNIPIP6_DEBUG_LEVEL < 4)
|
|
-#define nss_tunipip6_trace(s, ...)
|
|
-#else
|
|
-#define nss_tunipip6_trace(s, ...) pr_info("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__)
|
|
-#endif
|
|
-#endif
|
|
+ ntii->dev = dev;
|
|
+
|
|
+ /*
|
|
+ * Create statistics dentry.
|
|
+ */
|
|
+ if (!nss_tunipip6_stats_dentry_create(ntii)) {
|
|
+ vfree(ntii);
|
|
+ nss_tunipip6_warning("%px: Not able to create tunipip6 statistics dentry\n", dev);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ INIT_LIST_HEAD(&ntii->list);
|
|
+ ntii->inner_ifnum = inner_ifnum;
|
|
+ ntii->outer_ifnum = outer_ifnum;
|
|
+ dev_hold(dev);
|
|
+ return ntii;
|
|
+}
|
|
|
|
/*
|
|
- * Frag Id update is disabled by default
|
|
+ * nss_tunipip6_free_instance()
|
|
+ * Delete the tunipip6 interface instance from the list and free it.
|
|
+ *
|
|
+ * Note: tunnel list lock is expected to be held by the caller.
|
|
*/
|
|
-bool frag_id_update = false;
|
|
+static void nss_tunipip6_free_instance(struct nss_tunipip6_instance *ntii)
|
|
+{
|
|
+ if (!list_empty(&ntii->list)) {
|
|
+ list_del(&ntii->list);
|
|
+ }
|
|
+
|
|
+ vfree(ntii);
|
|
+}
|
|
+
|
|
/*
|
|
- * Creating custom ipip6 interface is disabled by default.
|
|
+ * nss_tunipip6_find_instance()
|
|
+ * Find tunipip6 interface instance from list.
|
|
+ *
|
|
+ * Note: tunnel list lock is expected to be held by the caller.
|
|
*/
|
|
-static bool enable_custom;
|
|
-module_param(enable_custom, bool, 0);
|
|
+struct nss_tunipip6_instance *nss_tunipip6_find_instance(struct net_device *dev)
|
|
+{
|
|
+ struct nss_tunipip6_instance *ntii;
|
|
+
|
|
+ /*
|
|
+ * Check if dev instance is in the list
|
|
+ */
|
|
+ list_for_each_entry(ntii, &tunipip6_ctx.dev_list, list) {
|
|
+ if (ntii->dev == dev) {
|
|
+ return ntii;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
|
|
/*
|
|
- * tunipip6 stats structure
|
|
+ * nss_tunipip6_find_and_free_instance()
|
|
+ * Find and free the tunipip6 instance.
|
|
*/
|
|
-struct nss_tunipip6_stats {
|
|
- uint32_t rx_packets; /* Number of received packets */
|
|
- uint32_t rx_bytes; /* Number of received bytes */
|
|
- uint32_t tx_packets; /* Number of transmitted packets */
|
|
- uint32_t tx_bytes; /* Number of transmitted bytes */
|
|
-};
|
|
+static enum nss_connmgr_tunipip6_err_codes nss_tunipip6_find_and_free_instance(struct net_device *netdev)
|
|
+{
|
|
+ struct dentry *dentry;
|
|
+ struct nss_tunipip6_instance *ntii;
|
|
+
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ ntii = nss_tunipip6_find_instance(netdev);
|
|
+ if (!ntii) {
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+ nss_tunipip6_warning("%px: Not able to find tunipip6 instance for dev:%s\n", netdev, netdev->name);
|
|
+ return NSS_CONNMGR_TUNIPIP6_CONTEXT_FAILURE;
|
|
+ }
|
|
+
|
|
+ dentry = ntii->dentry;
|
|
+ nss_tunipip6_free_instance(ntii);
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+ debugfs_remove(dentry);
|
|
+ dev_put(netdev);
|
|
+ return NSS_CONNMGR_TUNIPIP6_SUCCESS;
|
|
+}
|
|
|
|
/*
|
|
* nss_tunipip6_encap_exception()
|
|
@@ -289,20 +340,29 @@ static void nss_tunipip6_decap_exception
|
|
|
|
/*
|
|
* nss_tunipip6_update_dev_stats
|
|
- * Update the Dev stats received from NetAp
|
|
+ * Update the Dev stats received from NSS
|
|
*/
|
|
static void nss_tunipip6_update_dev_stats(struct net_device *dev,
|
|
- struct nss_tunipip6_stats_sync_msg *sync_stats)
|
|
+ struct nss_tunipip6_msg *tnlmsg)
|
|
{
|
|
struct pcpu_sw_netstats stats;
|
|
+ enum nss_dynamic_interface_type interface_type;
|
|
+ struct nss_tunipip6_stats_sync_msg *sync_stats = (struct nss_tunipip6_stats_sync_msg *)&tnlmsg->msg.stats_sync;
|
|
+
|
|
+ interface_type = nss_dynamic_interface_get_type(nss_tunipip6_get_context(), tnlmsg->cm.interface);
|
|
+
|
|
+ memset(&stats, 0, sizeof(stats));
|
|
+ if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER) {
|
|
+ stats.tx_packets = sync_stats->node_stats.tx_packets;
|
|
+ stats.tx_bytes = sync_stats->node_stats.tx_bytes;
|
|
+ } else if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER) {
|
|
+ stats.rx_packets = sync_stats->node_stats.rx_packets;
|
|
+ stats.rx_bytes = sync_stats->node_stats.rx_bytes;
|
|
+ } else {
|
|
+ nss_tunipip6_warning("%px: Invalid interface type received from NSS\n", dev);
|
|
+ return;
|
|
+ }
|
|
|
|
- u64_stats_init(&stats.syncp);
|
|
- u64_stats_update_begin(&stats.syncp);
|
|
- stats.rx_packets = sync_stats->node_stats.rx_packets;
|
|
- stats.rx_bytes = sync_stats->node_stats.rx_bytes;
|
|
- stats.tx_packets = sync_stats->node_stats.tx_packets;
|
|
- stats.tx_bytes = sync_stats->node_stats.tx_bytes;
|
|
- u64_stats_update_end(&stats.syncp);
|
|
dev->stats.rx_dropped += nss_cmn_rx_dropped_sum(&sync_stats->node_stats);
|
|
|
|
/* TODO: Update rx_dropped stats in ip6_update_offload_stats() */
|
|
@@ -316,11 +376,20 @@ static void nss_tunipip6_update_dev_stat
|
|
void nss_tunipip6_event_receive(void *if_ctx, struct nss_tunipip6_msg *tnlmsg)
|
|
{
|
|
struct net_device *netdev = NULL;
|
|
+
|
|
netdev = (struct net_device *)if_ctx;
|
|
|
|
switch (tnlmsg->cm.type) {
|
|
case NSS_TUNIPIP6_RX_STATS_SYNC:
|
|
- nss_tunipip6_update_dev_stats(netdev, (struct nss_tunipip6_stats_sync_msg *)&tnlmsg->msg.stats_sync);
|
|
+ /*
|
|
+ * Update netdevice statistics.
|
|
+ */
|
|
+ nss_tunipip6_update_dev_stats(netdev, tnlmsg);
|
|
+
|
|
+ /*
|
|
+ * Update NSS statistics for tunipip6.
|
|
+ */
|
|
+ nss_tunipip6_stats_sync(netdev, tnlmsg);
|
|
break;
|
|
|
|
default:
|
|
@@ -415,7 +484,7 @@ static void nss_tunipip6_dev_parse_param
|
|
tnlcfg->ttl_inherit = false;
|
|
tnlcfg->tos_inherit = true;
|
|
tnlcfg->frag_id_update = frag_id_update;
|
|
-
|
|
+ tnlcfg->fmr_max = NSS_TUNIPIP6_MAX_FMR;
|
|
/*
|
|
* Flow Label In kernel is stored in big endian format.
|
|
*/
|
|
@@ -454,9 +523,9 @@ static void nss_connmgr_tunipip6_configu
|
|
tunnel = (struct ip6_tnl *)netdev_priv(netdev);
|
|
|
|
/*
|
|
- * Configure FMR table up to NSS_TUNIPIP6_MAX_FMR_NUMBER, the rest will be forwarded to BR
|
|
+ * Configure FMR table up to NSS_TUNIPIP6_MAX_FMR, the rest will be forwarded to BR
|
|
*/
|
|
- for (fmr = tunnel->parms.fmrs; fmr && fmr_number < NSS_TUNIPIP6_MAX_FMR_NUMBER; fmr = fmr->next, fmr_number++) {
|
|
+ for (fmr = tunnel->parms.fmrs; fmr && fmr_number < NSS_TUNIPIP6_MAX_FMR; fmr = fmr->next, fmr_number++) {
|
|
/*
|
|
* Prepare "rulecfg"
|
|
*/
|
|
@@ -497,6 +566,7 @@ enum nss_connmgr_tunipip6_err_codes nss_
|
|
int inner_ifnum, outer_ifnum;
|
|
uint32_t features = 0;
|
|
nss_tx_status_t status;
|
|
+ struct nss_tunipip6_instance *ntii;
|
|
|
|
#if IS_ENABLED(CONFIG_MAP_E_SUPPORT)
|
|
#ifndef DRAFT03_SUPPORT
|
|
@@ -626,7 +696,7 @@ configure_tunnel:
|
|
status = nss_tunipip6_tx_sync(nss_ctx, &tnlmsg);
|
|
if (status != NSS_TX_SUCCESS) {
|
|
nss_tunipip6_warning("%px: Tunnel up command error %d\n", netdev, status);
|
|
- goto config_fail;
|
|
+ goto context_alloc_fail;
|
|
}
|
|
|
|
/*
|
|
@@ -644,12 +714,28 @@ configure_tunnel:
|
|
status = nss_tunipip6_tx_sync(nss_ctx, &tnlmsg);
|
|
if (status != NSS_TX_SUCCESS) {
|
|
nss_tunipip6_warning("%px: Tunnel up command error %d\n", netdev, status);
|
|
- goto config_fail;
|
|
+ goto context_alloc_fail;
|
|
}
|
|
|
|
+ /*
|
|
+ * Initialize tunipip6 instance.
|
|
+ */
|
|
+ ntii = nss_tunipip6_alloc_instance(netdev, inner_ifnum, outer_ifnum);
|
|
+ if (!ntii) {
|
|
+ nss_tunipip6_warning("%px: Not able to create tunipip6 instance\n", netdev);
|
|
+ goto context_alloc_fail;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Add the new tunipip6 instance to the global list.
|
|
+ */
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ list_add(&ntii->list, &tunipip6_ctx.dev_list);
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+
|
|
return NSS_CONNMGR_TUNIPIP6_SUCCESS;
|
|
|
|
-config_fail:
|
|
+context_alloc_fail:
|
|
nss_unregister_tunipip6_if(outer_ifnum);
|
|
outer_reg_fail:
|
|
nss_unregister_tunipip6_if(inner_ifnum);
|
|
@@ -675,6 +761,8 @@ EXPORT_SYMBOL(nss_connmgr_tunipip6_creat
|
|
*/
|
|
enum nss_connmgr_tunipip6_err_codes nss_connmgr_tunipip6_destroy_interface(struct net_device *netdev)
|
|
{
|
|
+ enum nss_connmgr_tunipip6_err_codes ret;
|
|
+
|
|
/*
|
|
* Validate netdev for ipv6-in-ipv4 Tunnel
|
|
*/
|
|
@@ -682,7 +770,20 @@ enum nss_connmgr_tunipip6_err_codes nss_
|
|
return NSS_CONNMGR_TUNIPIP6_NETDEV_TYPE_FAILURE;
|
|
}
|
|
|
|
- return _nss_tunipip6_dyn_interface_destroy(netdev);
|
|
+ /*
|
|
+ * Destroy tunipip6 NSS context.
|
|
+ */
|
|
+ ret = _nss_tunipip6_dyn_interface_destroy(netdev);
|
|
+ if (ret != NSS_CONNMGR_TUNIPIP6_SUCCESS) {
|
|
+ nss_tunipip6_warning("%px: Not able to destroy NSS context. Err: %d\n", netdev, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Find and free the tunipip6 instance.
|
|
+ */
|
|
+ ret = nss_tunipip6_find_and_free_instance(netdev);
|
|
+ return ret;
|
|
}
|
|
EXPORT_SYMBOL(nss_connmgr_tunipip6_destroy_interface);
|
|
|
|
@@ -941,6 +1042,39 @@ static int nss_tunipip6_dev_event(struct
|
|
}
|
|
|
|
/*
|
|
+ * nss_tunipip6_destroy_interface_all()
|
|
+ * Destroy NSS interfaces and free instance for all tunipip6 interfaces.
|
|
+ */
|
|
+static void nss_tunipip6_destroy_interface_all(void)
|
|
+{
|
|
+ struct net_device *netdev;
|
|
+ struct dentry *dentry;
|
|
+ struct nss_tunipip6_instance *ntii;
|
|
+
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ ntii = list_first_entry_or_null(&tunipip6_ctx.dev_list, struct nss_tunipip6_instance, list);
|
|
+ do {
|
|
+ if (!ntii) {
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ netdev = ntii->dev;
|
|
+ dentry = ntii->dentry;
|
|
+ nss_tunipip6_free_instance(ntii);
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+
|
|
+ dev_put(netdev);
|
|
+ debugfs_remove(dentry);
|
|
+ _nss_tunipip6_dyn_interface_destroy(netdev);
|
|
+
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ ntii = list_first_entry_or_null(&tunipip6_ctx.dev_list, struct nss_tunipip6_instance, list);
|
|
+ } while (ntii);
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+}
|
|
+
|
|
+/*
|
|
* Linux Net device Notifier
|
|
*/
|
|
struct notifier_block nss_tunipip6_notifier = {
|
|
@@ -965,6 +1099,20 @@ int __init nss_tunipip6_init_module(void
|
|
NSS_CLIENT_BUILD_ID);
|
|
|
|
/*
|
|
+ * Initialize lock and dev list.
|
|
+ */
|
|
+ INIT_LIST_HEAD(&tunipip6_ctx.dev_list);
|
|
+ spin_lock_init(&tunipip6_ctx.lock);
|
|
+
|
|
+ /*
|
|
+ * Create the debugfs directory for statistics.
|
|
+ */
|
|
+ if (!nss_tunipip6_stats_dentry_init()) {
|
|
+ nss_tunipip6_trace("Failed to initialize debugfs\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
* Do not register net device notification for
|
|
* custom tunnel. Net device notification is used only
|
|
* for standard tunnel.
|
|
@@ -1000,6 +1148,16 @@ void __exit nss_tunipip6_exit_module(voi
|
|
#endif
|
|
|
|
/*
|
|
+ * Free Host and NSS tunipip6 instances.
|
|
+ */
|
|
+ nss_tunipip6_destroy_interface_all();
|
|
+
|
|
+ /*
|
|
+ * De-initialize debugfs.
|
|
+ */
|
|
+ nss_tunipip6_stats_dentry_deinit();
|
|
+
|
|
+ /*
|
|
* Unregister net device notification for standard tunnel.
|
|
*/
|
|
if (!enable_custom) {
|
|
--- /dev/null
|
|
+++ b/tunipip6/nss_connmgr_tunipip6_priv.h
|
|
@@ -0,0 +1,94 @@
|
|
+/*
|
|
+ **************************************************************************
|
|
+ * Copyright (c) 2020, 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.
|
|
+ **************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __NSS_CONNMGR_TUNIPIP6_PRIV_H_
|
|
+#define __NSS_CONNMGR_TUNIPIP6_PRIV_H_
|
|
+
|
|
+#include "nss_connmgr_tunipip6_stats.h"
|
|
+#include <linux/debugfs.h>
|
|
+
|
|
+/*
|
|
+ * tunipip6 context
|
|
+ */
|
|
+extern struct nss_tunipip6_context tunipip6_ctx;
|
|
+
|
|
+/*
|
|
+ * NSS tunipip6 debug macros
|
|
+ */
|
|
+#if (NSS_TUNIPIP6_DEBUG_LEVEL < 1)
|
|
+#define nss_tunipip6_assert(fmt, args...)
|
|
+#else
|
|
+#define nss_tunipip6_assert(c) if (!(c)) { BUG_ON(!(c)); }
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Compile messages for dynamic enable/disable
|
|
+ */
|
|
+#if defined(CONFIG_DYNAMIC_DEBUG)
|
|
+#define nss_tunipip6_warning(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#define nss_tunipip6_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#define nss_tunipip6_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#else /* CONFIG_DYNAMIC_DEBUG */
|
|
+/*
|
|
+ * Statically compile messages at different levels
|
|
+ */
|
|
+#if (NSS_TUNIPIP6_DEBUG_LEVEL < 2)
|
|
+#define nss_tunipip6_warning(s, ...)
|
|
+#else
|
|
+#define nss_tunipip6_warning(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#endif
|
|
+
|
|
+#if (NSS_TUNIPIP6_DEBUG_LEVEL < 3)
|
|
+#define nss_tunipip6_info(s, ...)
|
|
+#else
|
|
+#define nss_tunipip6_info(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#endif
|
|
+
|
|
+#if (NSS_TUNIPIP6_DEBUG_LEVEL < 4)
|
|
+#define nss_tunipip6_trace(s, ...)
|
|
+#else
|
|
+#define nss_tunipip6_trace(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
|
+#endif
|
|
+#endif /* CONFIG_DYNAMIC_DEBUG */
|
|
+
|
|
+extern struct nss_tunipip6_context tunipip6_ctx;
|
|
+
|
|
+/*
|
|
+ * tunipip6 global context structure.
|
|
+ */
|
|
+struct nss_tunipip6_context {
|
|
+ struct list_head dev_list; /* List of tunipip6 interface instances */
|
|
+ struct dentry *tunipip6_dentry_dir; /* tunipip6 debugfs directory entry */
|
|
+ spinlock_t lock; /* Lock to protect list. */
|
|
+};
|
|
+
|
|
+/*
|
|
+ * tunipip6 interface instance structure.
|
|
+ */
|
|
+struct nss_tunipip6_instance {
|
|
+ struct list_head list; /* List of tunipip6 interface instance */
|
|
+ struct net_device *dev; /* tunipip6 netdevice */
|
|
+ struct dentry *dentry; /* debugfs entry for this tunnel device */
|
|
+ struct nss_tunipip6_stats stats; /* tunipip6 statistics */
|
|
+ uint32_t inner_ifnum; /* tunipip6 inner dynamic interface */
|
|
+ uint32_t outer_ifnum; /* tunipip6 outer dynamic interface */
|
|
+};
|
|
+
|
|
+struct nss_tunipip6_instance *nss_tunipip6_find_instance(struct net_device *dev);
|
|
+
|
|
+#endif /* __NSS_CONNMGR_TUNIPIP6_PRIV_H_ */
|
|
--- /dev/null
|
|
+++ b/tunipip6/nss_connmgr_tunipip6_stats.c
|
|
@@ -0,0 +1,225 @@
|
|
+/*
|
|
+ **************************************************************************
|
|
+ * Copyright (c) 2020, 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.
|
|
+ **************************************************************************
|
|
+ */
|
|
+
|
|
+#include <nss_api_if.h>
|
|
+#include "nss_connmgr_tunipip6_priv.h"
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_str
|
|
+ * tunipip6 statistics strings for NSS tunnel stats
|
|
+ */
|
|
+static int8_t *nss_tunipip6_stats_str[NSS_TUNIPIP6_STATS_MAX] = {
|
|
+ "rx pkts",
|
|
+ "rx bytes",
|
|
+ "tx pkts",
|
|
+ "tx bytes",
|
|
+ "rx queue 0 dropped",
|
|
+ "rx queue 1 dropped",
|
|
+ "rx queue 2 dropped",
|
|
+ "rx queue 3 dropped",
|
|
+ "encap low headroom",
|
|
+ "encap unhandled_protocol",
|
|
+ "encap enqueue fail",
|
|
+ "encap tunnel exist",
|
|
+ "encap total fmr_count",
|
|
+ "encap fmr add count",
|
|
+ "encap fmr del count",
|
|
+ "encap fmr flush count",
|
|
+ "encap fmr update_count",
|
|
+ "encap fmr add_fail count",
|
|
+ "encap fmr del_fail count",
|
|
+ "encap error no fmr",
|
|
+ "encap bmr add count",
|
|
+ "encap bmr del count",
|
|
+ "encap error bmr exist",
|
|
+ "encap error no bmr",
|
|
+ "decap enqueue fail",
|
|
+};
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_show()
|
|
+ * Read tunipip6 tunnel statistics
|
|
+ */
|
|
+static int nss_tunipip6_stats_show(struct seq_file *m, void __attribute__((unused))*p)
|
|
+{
|
|
+ int i;
|
|
+ struct nss_tunipip6_instance *tun_inst;
|
|
+ struct nss_tunipip6_stats *tunipip6_tunnel_stats;
|
|
+
|
|
+ tun_inst = vzalloc(sizeof(struct nss_tunipip6_instance));
|
|
+ if (!tun_inst) {
|
|
+ nss_tunipip6_warning("Failed to allocate memory for tun_inst\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ tunipip6_tunnel_stats = vzalloc(sizeof(struct nss_tunipip6_stats));
|
|
+ if (!tunipip6_tunnel_stats) {
|
|
+ nss_tunipip6_warning("Failed to allocate memory for tunipip6_tunnel_stats\n");
|
|
+ vfree(tun_inst);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Copy the tunnel and stats information from the tunnel instance.
|
|
+ */
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ memcpy(tun_inst, m->private, sizeof(struct nss_tunipip6_instance));
|
|
+ memcpy(tunipip6_tunnel_stats, &tun_inst->stats, sizeof(struct nss_tunipip6_stats));
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+
|
|
+ seq_printf(m, "\n\tInner ifnum %u stats:\n", tun_inst->inner_ifnum);
|
|
+ for (i = 0; i < NSS_TUNIPIP6_STATS_MAX; i++) {
|
|
+ seq_printf(m, "\t\t%s = %llu\n",
|
|
+ nss_tunipip6_stats_str[i],
|
|
+ tunipip6_tunnel_stats->inner_stats[i]);
|
|
+ }
|
|
+
|
|
+ seq_printf(m, "\n\tOuter ifnum %u stats:\n", tun_inst->outer_ifnum);
|
|
+ for (i = 0; i < NSS_TUNIPIP6_STATS_MAX; i++) {
|
|
+ seq_printf(m, "\t\t%s = %llu\n",
|
|
+ nss_tunipip6_stats_str[i],
|
|
+ tunipip6_tunnel_stats->outer_stats[i]);
|
|
+ }
|
|
+
|
|
+ seq_printf(m, "\n%s tunnel stats end\n\n", tun_inst->dev->name);
|
|
+ vfree(tun_inst);
|
|
+ vfree(tunipip6_tunnel_stats);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_open()
|
|
+ */
|
|
+static int nss_tunipip6_stats_open(struct inode *inode, struct file *file)
|
|
+{
|
|
+ return single_open(file, nss_tunipip6_stats_show, inode->i_private);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_update()
|
|
+ * Update inner or outer node statistics
|
|
+ */
|
|
+static void nss_tunipip6_stats_update(uint64_t *stats, struct nss_tunipip6_stats_sync_msg *stats_msg)
|
|
+{
|
|
+ uint32_t i, *src;
|
|
+ uint64_t *dest = stats;
|
|
+
|
|
+ src = &stats_msg->node_stats.rx_packets;
|
|
+ for (i = NSS_TUNIPIP6_STATS_RX_PKTS; i < NSS_TUNIPIP6_STATS_MAX; i++, src++, dest++) {
|
|
+ *dest += *src;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_sync()
|
|
+ * Sync function for tunipip6 statistics
|
|
+ */
|
|
+void nss_tunipip6_stats_sync(struct net_device *dev, struct nss_tunipip6_msg *ntm)
|
|
+{
|
|
+ uint32_t ifnum = ntm->cm.interface;
|
|
+ struct nss_tunipip6_stats_sync_msg *stats = &ntm->msg.stats_sync;
|
|
+ struct nss_tunipip6_instance *ntii;
|
|
+ struct nss_tunipip6_stats *s;
|
|
+
|
|
+ spin_lock_bh(&tunipip6_ctx.lock);
|
|
+ ntii = nss_tunipip6_find_instance(dev);
|
|
+ if (!ntii) {
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+ nss_tunipip6_warning("%px: Not able to find context for device: %s\n", dev, dev->name);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ s = &ntii->stats;
|
|
+ if (ntii->inner_ifnum == ifnum) {
|
|
+ nss_tunipip6_stats_update(s->inner_stats, stats);
|
|
+ } else if (ntii->outer_ifnum == ifnum) {
|
|
+ nss_tunipip6_stats_update(s->outer_stats, stats);
|
|
+ } else {
|
|
+ nss_tunipip6_warning("%px: Netdev=%s invalid interface number. Interface No: %u\n", dev, dev->name, ifnum);
|
|
+ }
|
|
+
|
|
+ spin_unlock_bh(&tunipip6_ctx.lock);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_ops
|
|
+ * File operations for tunipip6 tunnel stats
|
|
+ */
|
|
+static const struct file_operations nss_tunipip6_stats_ops = { \
|
|
+ .open = nss_tunipip6_stats_open,
|
|
+ .read = seq_read,
|
|
+ .llseek = seq_lseek,
|
|
+ .release = seq_release
|
|
+};
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_dentry_destroy()
|
|
+ * Remove debufs file for given tunnel.
|
|
+ */
|
|
+void nss_tunipip6_stats_dentry_destroy(struct nss_tunipip6_instance *tun_inst)
|
|
+{
|
|
+ debugfs_remove(tun_inst->dentry);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_dentry_create()
|
|
+ * Create dentry for a given tunnel.
|
|
+ */
|
|
+bool nss_tunipip6_stats_dentry_create(struct nss_tunipip6_instance *tun_inst)
|
|
+{
|
|
+ char dentry_name[IFNAMSIZ];
|
|
+
|
|
+ scnprintf(dentry_name, sizeof(dentry_name), "%s", tun_inst->dev->name);
|
|
+ tun_inst->dentry = debugfs_create_file(dentry_name, S_IRUGO,
|
|
+ tunipip6_ctx.tunipip6_dentry_dir, tun_inst, &nss_tunipip6_stats_ops);
|
|
+ if (!tun_inst->dentry) {
|
|
+ nss_tunipip6_warning("Debugfs file creation failed for tun %s\n", tun_inst->dev->name);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_dentry_deinit()
|
|
+ * Cleanup the debugfs tree.
|
|
+ */
|
|
+void nss_tunipip6_stats_dentry_deinit(void)
|
|
+{
|
|
+ if (tunipip6_ctx.tunipip6_dentry_dir) {
|
|
+ debugfs_remove_recursive(tunipip6_ctx.tunipip6_dentry_dir);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * nss_tunipip6_stats_dentry_init()
|
|
+ * Create tunipip6 tunnel statistics debugfs entry.
|
|
+ */
|
|
+bool nss_tunipip6_stats_dentry_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Initialize debugfs directory.
|
|
+ */
|
|
+ tunipip6_ctx.tunipip6_dentry_dir = debugfs_create_dir("qca-nss-tunipip6", NULL);
|
|
+ if (!tunipip6_ctx.tunipip6_dentry_dir) {
|
|
+ nss_tunipip6_warning("Failed to create debug entry for subsystem: qca-nss-tunipip6\n");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/tunipip6/nss_connmgr_tunipip6_stats.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ ******************************************************************************
|
|
+ * Copyright (c) 2020, 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.
|
|
+ * ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef _NSS_CONNMGR_TUNIPIP6_STATS_H_
|
|
+#define _NSS_CONNMGR_TUNIPIP6_STATS_H_
|
|
+
|
|
+struct nss_tunipip6_instance;
|
|
+
|
|
+/*
|
|
+ * tunipip6 statistic counters
|
|
+ */
|
|
+enum nss_tunipip6_stats_type {
|
|
+ NSS_TUNIPIP6_STATS_RX_PKTS,
|
|
+ NSS_TUNIPIP6_STATS_RX_BYTES,
|
|
+ NSS_TUNIPIP6_STATS_TX_PKTS,
|
|
+ NSS_TUNIPIP6_STATS_TX_BYTES,
|
|
+ NSS_TUNIPIP6_STATS_RX_QUEUE_0_DROPPED,
|
|
+ NSS_TUNIPIP6_STATS_RX_QUEUE_1_DROPPED,
|
|
+ NSS_TUNIPIP6_STATS_RX_QUEUE_2_DROPPED,
|
|
+ NSS_TUNIPIP6_STATS_RX_QUEUE_3_DROPPED,
|
|
+ NSS_TUNIPIP6_STATS_EXCEP_ENCAP_LOW_HEADROOM,
|
|
+ NSS_TUNIPIP6_STATS_EXCEP_ENCAP_UNHANDLED_PROTOCOL,
|
|
+ NSS_TUNIPIP6_STATS_DROP_ENCAP_ENQUEUE_FAIL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ERR_TUNNEL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_TOTAL_FMR,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_ADD,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_DEL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_FLUSH,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_UPDATE,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_ADD_FAIL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_FMR_DEL_FAIL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_ERR_NO_FMR,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_BMR_ADD,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_BMR_DEL,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_ERR_BMR_EXIST,
|
|
+ NSS_TUNIPIP6_STATS_CONFIG_ENCAP_ERR_NO_BMR,
|
|
+ NSS_TUNIPIP6_STATS_DROP_DECAP_ENQUEUE_FAIL,
|
|
+ NSS_TUNIPIP6_STATS_MAX,
|
|
+};
|
|
+
|
|
+/*
|
|
+ * tunipip6 statistics
|
|
+ */
|
|
+struct nss_tunipip6_stats {
|
|
+ uint64_t inner_stats[NSS_TUNIPIP6_STATS_MAX];
|
|
+ uint64_t outer_stats[NSS_TUNIPIP6_STATS_MAX];
|
|
+};
|
|
+
|
|
+/*
|
|
+ * tunipip6 statistics API
|
|
+ */
|
|
+extern void nss_tunipip6_stats_sync(struct net_device *dev, struct nss_tunipip6_msg *ntm);
|
|
+extern void nss_tunipip6_stats_dentry_deinit(void);
|
|
+extern bool nss_tunipip6_stats_dentry_init(void);
|
|
+extern void nss_tunipip6_stats_dentry_destroy(struct nss_tunipip6_instance *tun_inst);
|
|
+extern bool nss_tunipip6_stats_dentry_create(struct nss_tunipip6_instance *tun_inst);
|
|
+
|
|
+#endif /* _NSS_CONNMGR_TUNIPIP6_STATS_H_ */
|
|
--- a/tunipip6/nss_connmgr_tunipip6_sysctl.c
|
|
+++ b/tunipip6/nss_connmgr_tunipip6_sysctl.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
**************************************************************************
|
|
- * Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
|
+ * Copyright (c) 2020-2021, 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
|
|
@@ -61,7 +61,7 @@ static int nss_tunipip6_data_parser(stru
|
|
bool ipv4_prefix_valid = false, ipv4_prefix_len_valid = false, ipv6_suffix_len_valid = false;
|
|
bool rule_type_valid = false, ea_len_valid = false, psid_offset_valid = false, netdev_valid = false;
|
|
struct nss_connmgr_tunipip6_maprule_cfg mrcfg = {0};
|
|
- char *buf = kzalloc(MAX_PROC_SIZE, GFP_KERNEL);
|
|
+ char *buf;
|
|
enum nss_connmgr_tunipip6_err_codes status;
|
|
struct net_device *dev = NULL;
|
|
char *pfree;
|
|
@@ -69,7 +69,11 @@ static int nss_tunipip6_data_parser(stru
|
|
int ret;
|
|
int count;
|
|
|
|
+ if (!write) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
+ buf = kzalloc(MAX_PROC_SIZE, GFP_KERNEL);
|
|
if (!buf) {
|
|
return -ENOMEM;
|
|
}
|
|
@@ -122,6 +126,7 @@ static int nss_tunipip6_data_parser(stru
|
|
|
|
if ((rule_type !=NSS_CONNMGR_TUNIPIP6_RULE_BMR) &&
|
|
(rule_type != NSS_CONNMGR_TUNIPIP6_RULE_FMR)) {
|
|
+ kfree(pfree);
|
|
goto fail;
|
|
}
|
|
rule_type_valid = true;
|
|
@@ -135,6 +140,7 @@ static int nss_tunipip6_data_parser(stru
|
|
}
|
|
|
|
if (frag_id != 0 && frag_id != 1) {
|
|
+ kfree(pfree);
|
|
goto fail;
|
|
}
|
|
continue;
|
|
@@ -396,9 +402,9 @@ static int nss_tunipip6_cmd_procfs_read_
|
|
b. To delete maprule(BMR):\n\
|
|
echo dev=<map-mape/MAP-E netdevice> rule_type=<1> > remove_map_rule\n\
|
|
3. To flush FMR entries:\n\
|
|
- echo dev=<map-mape/MAP-E netdevice> > flush_fmr_rule\n\
|
|
- 4. To enable/disable frag id:\n\
|
|
- echo frag_id_update=<0/1> > frag_id\n\
|
|
+ echo dev=<map-mape/MAP-E netdevice> > flush_fmr_rule\n");
|
|
+ pr_info("\t\t\t4. To enable/disable frag id: \n\
|
|
+ echo frag_id_update=<0/1> > frag_id \n\
|
|
=====end of help=====\n");
|
|
*lenp = 0;
|
|
return ret;
|