blob: 2368a089b15e6b97ed4cc61bcfca649feab4174e [file] [log] [blame]
/*
***************************************************************************
* 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 <linux/sysctl.h>
#include <linux/string.h>
#include "nss_mirror_public.h"
#include "nss_mirror.h"
#define NSS_MIRROR_CONFIG_PARAM_NUM 3
#define NSS_MIRROR_SET_NEXTHOP_PARAM_NUM 2
#define NSS_MIRROR_ENABLE_INGRESS_PMC_NUM 2
/*
* nss_mirror_ctl_cmd_type
* Mirror command types.
*/
enum nss_mirror_ctl_cmd_type {
NSS_MIRROR_CMD_UNKNOWN, /* Unknown command. */
NSS_MIRROR_CMD_CREATE, /* Create command. */
NSS_MIRROR_CMD_CONFIGURE, /* Configure command. */
NSS_MIRROR_CMD_SET_NEXTHOP, /* Set nexthop command. */
NSS_MIRROR_CMD_RESET_NEXTHOP, /* Reset nexthop command. */
NSS_MIRROR_CMD_INGRESS_PMC_ENABLE, /* Ingress promiscuous enable command. */
NSS_MIRROR_CMD_INGRESS_PMC_DISABLE, /* Ingress promiscuous disable command. */
NSS_MIRROR_CMD_ENABLE, /* Enable command. */
NSS_MIRROR_CMD_DISABLE, /* Disable command. */
NSS_MIRROR_CMD_DISPLAY, /* Display command. */
NSS_MIRROR_CMD_DESTROY, /* Destroy command. */
NSS_MIRROR_CMD_HELP, /* Help command. */
};
/*
* Sysctl table header for mirror.
*/
static struct ctl_table_header *nss_mirror_ctl_header;
/*
* Mirror config data.
*/
static unsigned char nss_mirror_config_data[128] __read_mostly;
/*
* nss_mirror_ctl_read_nextarg()
* API to read the next argument in the command.
*/
static char *nss_mirror_ctl_read_nextarg(char **buf_ptr)
{
if (!buf_ptr || !(*buf_ptr)) {
nss_mirror_warn("Read Buf is NULL\n");
return NULL;
}
return strsep(buf_ptr, " ");
}
/*
* nss_mirror_ctl_read_value()
* API to read a value of the param in the command.
*/
static char *nss_mirror_ctl_read_value(char **buf_ptr, char **value_ptr, char *delim)
{
*value_ptr = nss_mirror_ctl_read_nextarg(buf_ptr);
if (!(*value_ptr)) {
return NULL;
}
return strsep(value_ptr, delim);
}
/*
* nss_mirror_ctl_convert_char_to_u32()
* API to convert character to u32.
*/
static int nss_mirror_ctl_convert_char_to_u32(char *buf, uint32_t *arg)
{
int ret;
/*
* Write the tokens to unsigned integer.
*/
ret = sscanf(buf, "%u", arg);
if (ret != 1) {
nss_mirror_warn("Failed to write the %s token to u32\n", buf);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_convert_char_to_u16()
* API to convert character to u16.
*/
static int nss_mirror_ctl_convert_char_to_u16(char *buf, uint16_t *arg)
{
int ret;
/*
* Write the tokens to unsigned short integer.
*/
ret = sscanf(buf, "%hu", arg);
if (ret != 1) {
nss_mirror_warn("Failed to write the %s token to u16\n", buf);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_get_netdev_by_name()
* API to get netdev from name.
*
* Note: Caller is expected to release the hold on the dev.
*/
static int nss_mirror_ctl_get_netdev_by_name(char *name, struct net_device **dev)
{
char dev_name[IFNAMSIZ] = {0};
strlcpy(dev_name, name, IFNAMSIZ);
if (dev_name[strlen(dev_name) - 1] == '\n') {
dev_name[strlen(dev_name) - 1] = '\0';
}
nss_mirror_info("Device name: %s\n", dev_name);
*dev = dev_get_by_name(&init_net, dev_name);
if (!*dev) {
nss_mirror_warn("Cannot find %s netdevice\n", dev_name);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_display_help()
* API to display help.
*/
static void nss_mirror_ctl_display_help(void)
{
pr_info("Usage: \n"
"echo create > <REDIRECT PATH>\n"
"echo configure mirrordev=<mirror dev name> [mirror_size=<MIRROR SIZE>]"
" [mirror_point=<MIRROR POINT>] [mirror_offset=<MIRROR OFFSET>] > <REDIRECT PATH>\n"
"echo enable mirrordev=<mirror dev name> > <REDIRECT PATH>\n"
"echo disable mirrordev=<mirror dev name> > <REDIRECT PATH>\n"
"echo set_nexthop mirrordev=<mirror dev name> mirror_next_hop=n2h/eth_rx\n > <REDIRECT PATH>"
"echo reset_nexthop mirrordev=<mirror dev name> > <REDIRECT PATH>\n"
"echo ingress_pmc_enable devname=<eth/ath dev name> mirrordev=<mirror dev name> > <REDIRECT PATH>\n"
"echo ingress_pmc_disable devname=<eth/ath dev name> > <REDIRECT PATH>\n"
"echo display [mirrordev=<dev name> / all] > <REDIRECT PATH>\n"
"echo destroy mirrordev=<mirror dev name> > <REDIRECT PATH>\n"
"Where,\n"
"\t<REDIRECT PATH> = /proc/sys/dev/nss/mirror/config\n"
);
}
/*
* nss_mirror_ctl_parse_reset_nexthop_cmd()
* API to parse reset nexthop command.
*/
static int nss_mirror_ctl_parse_reset_nexthop_cmd(char *buffer)
{
struct net_device *mirror_dev;
char *param, *value;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid param: %s in promiscuous enable cmd\n", value);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
if (nss_mirror_reset_nexthop(mirror_dev)) {
nss_mirror_warn("Error in sending reset nexthop config to mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_set_nexthop_cmd()
* API to parse set nexthop command.
*/
static int nss_mirror_ctl_parse_set_nexthop_cmd(char *buffer)
{
struct net_device *mirror_dev = NULL;
char *param, *value;
int32_t nexthop_if_num = -1;
uint8_t param_num = NSS_MIRROR_SET_NEXTHOP_PARAM_NUM;
do {
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (!strcmp(param, "mirrordev")) {
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
} else if (!strcmp(param, "mirror_next_hop")) {
if (value[strlen(value) - 1] == '\n') {
value[strlen(value) - 1] = '\0';
}
if (!strcmp(value, "eth_rx")) {
nexthop_if_num = NSS_ETH_RX_INTERFACE;
} else if (!strcmp(value, "n2h")) {
nexthop_if_num = NSS_N2H_INTERFACE;
} else {
if (mirror_dev) {
dev_put(mirror_dev);
}
nss_mirror_warn("Invalid mirror next hop value %s\n", value);
return -1;
}
} else {
if (mirror_dev) {
dev_put(mirror_dev);
}
nss_mirror_warn("Invalid param: %s in promiscuous enable cmd\n", value);
return -1;
}
} while (--param_num);
if (!mirror_dev) {
nss_mirror_warn("Mirror device is NULL\n");
return -1;
}
if (nexthop_if_num < 0) {
nss_mirror_warn("Invalid nexthop interface number\n");
dev_put(mirror_dev);
return -1;
}
if (nss_mirror_set_nexthop(mirror_dev, nexthop_if_num)) {
nss_mirror_warn("Error in sending set nexthop config to mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_disable_cmd()
* API to parse disable command.
*/
static int nss_mirror_ctl_parse_disable_cmd(char *buffer)
{
struct net_device *mirror_dev;
char *param, *value;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid parameter %s in disable cmd\n", param);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
if (nss_mirror_disable(mirror_dev)) {
nss_mirror_warn("Error in sending disable config to mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_enable_cmd()
* API to parse enable command.
*/
static int nss_mirror_ctl_parse_enable_cmd(char *buffer)
{
struct net_device *mirror_dev;
char *param, *value;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid parameter %s in enable cmd\n", param);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
if (nss_mirror_enable(mirror_dev)) {
nss_mirror_warn("Error in sending enable config to mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_display_cmd()
* API to parse display command.
*/
static int nss_mirror_ctl_parse_display_cmd(char *buffer)
{
char *param, *value;
char dev_name[IFNAMSIZ] = {0};
struct net_device *mirror_dev;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid param %s in mirror display cmd\n", param);
return -1;
}
strlcpy(dev_name, value, IFNAMSIZ);
if (dev_name[strlen(dev_name) - 1] == '\n') {
dev_name[strlen(dev_name) - 1] = '\0';
}
nss_mirror_info("dev name: %s\n", dev_name);
if (!strcmp(dev_name, "all")) {
nss_mirror_display_all_info();
return 0;
}
mirror_dev = dev_get_by_name(&init_net, dev_name);
if (!mirror_dev) {
nss_mirror_warn("Cannot find the %s netdevice\n", dev_name);
return -1;
}
/*
* Verify the mirror netdevice.
*/
if (nss_cmn_get_interface_number_by_dev_and_type(mirror_dev, NSS_DYNAMIC_INTERFACE_TYPE_MIRROR) < 0) {
dev_put(mirror_dev);
nss_mirror_warn("No valid NSS FW interface for %s device\n", dev_name);
return -1;
}
nss_mirror_display_info(mirror_dev);
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_enable_ingress_pmc_cmd()
* API to parse ingress promiscuous enable command.
*/
static int nss_mirror_ctl_parse_enable_ingress_pmc_cmd(char *buffer)
{
char *param, *value;
struct nss_ctx_instance *nss_ctx;
struct net_device *dev, *mirror_dev = NULL;
nss_tx_status_t status;
int32_t if_num = -1, type = 0, mirror_if_num = -1;
uint8_t param_num = NSS_MIRROR_ENABLE_INGRESS_PMC_NUM;
do {
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (!strcmp(param, "devname")) {
if (nss_mirror_ctl_get_netdev_by_name(value, &dev) < 0) {
nss_mirror_warn("Error in getting devname net device.\n");
if (mirror_dev) {
dev_put(mirror_dev);
}
return -1;
}
if ((if_num = nss_cmn_get_interface_number_by_dev(dev)) < 0) {
nss_mirror_warn("No valid NSS FW interface for %s device\n", dev->name);
if (mirror_dev) {
dev_put(mirror_dev);
}
dev_put(dev);
return -1;
}
dev_put(dev);
} else if (!strcmp(param, "mirrordev")) {
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
/*
* Verify the mirror netdevice.
*/
if ((mirror_if_num = nss_cmn_get_interface_number_by_dev_and_type(mirror_dev, NSS_DYNAMIC_INTERFACE_TYPE_MIRROR)) < 0) {
nss_mirror_warn("No valid NSS FW interface for %s device\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
} else {
if (mirror_dev) {
dev_put(mirror_dev);
}
nss_mirror_warn("Invalid param: %s in promiscuous enable cmd\n", value);
return -1;
}
} while (--param_num);
if (!mirror_dev) {
nss_mirror_warn("Mirror device is NULL\n");
return -1;
}
if ((if_num < 0) || (mirror_if_num < 0)) {
nss_mirror_warn("Invalid interface number\n");
dev_put(mirror_dev);
return -1;
}
/*
* Return if the mirror interface is in open state.
*/
if (mirror_dev->flags & IFF_UP) {
nss_mirror_warn("%s mirror interface is in open state\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
nss_ctx = nss_mirror_get_context();
if (!nss_ctx) {
nss_mirror_warn("Invalid NSS context\n");
return -1;
}
type = nss_dynamic_interface_get_type(nss_ctx, if_num);
if (type == NSS_DYNAMIC_INTERFACE_TYPE_VAP) {
status = nss_wifi_vdev_set_next_hop(nss_wifi_get_context(), if_num, mirror_if_num);
} else if (if_num < NSS_MAX_PHYSICAL_INTERFACES) {
status = nss_phys_if_set_nexthop(nss_ctx, if_num, mirror_if_num);
} else {
nss_mirror_warn("Invalid nexthop interface:%d type:%d\n", if_num, type);
return -1;
}
if (status != NSS_TX_SUCCESS) {
nss_mirror_warn("Setting nexthop failed. if_num: %u, nexthop: %u\n", if_num, mirror_if_num);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_parse_disable_ingress_pmc_cmd()
* API to parse ingress promiscuous disable command.
*/
static int nss_mirror_ctl_parse_disable_ingress_pmc_cmd(char *buffer)
{
char *param, *value;
struct nss_ctx_instance *nss_ctx;
struct net_device *dev;
nss_tx_status_t status;
int32_t if_num, type = 0;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "devname")) {
nss_mirror_warn("Invalid param: %s in promiscuous enable cmd\n", value);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &dev) < 0) {
nss_mirror_warn("Error in getting devname net device.\n");
return -1;
}
if ((if_num = nss_cmn_get_interface_number_by_dev(dev)) < 0) {
nss_mirror_warn("No valid NSS FW interface for %s device\n", dev->name);
dev_put(dev);
return -1;
}
dev_put(dev);
nss_ctx = nss_mirror_get_context();
if (!nss_ctx) {
nss_mirror_warn("Invalid NSS context\n");
return -1;
}
type = nss_dynamic_interface_get_type(nss_ctx, if_num);
if (type == NSS_DYNAMIC_INTERFACE_TYPE_VAP) {
status = nss_mirror_reset_if_nexthop(if_num);
} else if (if_num < NSS_MAX_PHYSICAL_INTERFACES) {
status = nss_phys_if_reset_nexthop(nss_ctx, if_num);
} else {
nss_mirror_warn("Reset nexthop failed for %d interface, type:%d\n", if_num, type);
return -1;
}
if (status != NSS_TX_SUCCESS) {
nss_mirror_warn("Re-setting nexthop failed for if_num: %u\n", if_num);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_parse_destroy_cmd()
* API to parse destroy command.
*/
static int nss_mirror_ctl_parse_destroy_cmd(char *buffer)
{
struct net_device *mirror_dev;
char *param, *value;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid param %s in mirror delete command\n", param);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
/*
* Deconfigure mirror interface.
*/
if (nss_mirror_deconfigure_mirror(mirror_dev) < 0) {
nss_mirror_warn("Error in deconfiguring mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
if (nss_mirror_destroy(mirror_dev)) {
nss_mirror_warn("Error in sending delete config to mirror interface: %s\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_parse_config_param()
* API to parse configure parameters.
*/
static int nss_mirror_ctl_parse_config_param(char *buffer, uint16_t *size_ptr,
enum nss_mirror_pkt_clone_point *pt_ptr, uint16_t *offset_ptr)
{
uint8_t param_num = NSS_MIRROR_CONFIG_PARAM_NUM;
char *param, *value;
do {
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
/*
* No configure parameter is given. Use the default configure values.
*/
if (!param || !value) {
return 0;
}
if (!strcmp(param, "mirror_size")) {
if (nss_mirror_ctl_convert_char_to_u16(value, size_ptr)) {
nss_mirror_warn("Not able to parse %s to u16\n", value);
return -1;
}
} else if (!strcmp(param, "mirror_point")) {
if (nss_mirror_ctl_convert_char_to_u32(value, pt_ptr)) {
nss_mirror_warn("Not able to parse %s to u32\n", value);
return -1;
}
} else if (!strcmp(param, "mirror_offset")) {
if (nss_mirror_ctl_convert_char_to_u16(value, offset_ptr)) {
nss_mirror_warn("Not able to parse %s to u16\n", value);
return -1;
}
} else {
nss_mirror_warn("Invalid param:%s in create cmd\n", param);
return -1;
}
} while (--param_num);
return 0;
}
/*
* nss_mirror_ctl_parse_configure_cmd()
* API to parse configure command.
*/
static int nss_mirror_ctl_parse_configure_cmd(char *buffer)
{
struct net_device *mirror_dev;
char *param, *value;
enum nss_mirror_pkt_clone_point mirror_point = NSS_MIRROR_PKT_CLONE_POINT_DEFAULT;
uint16_t mirror_size = 0;
uint16_t mirror_offset = 0;
param = nss_mirror_ctl_read_value(&buffer, &value, "=");
if (!param || !value) {
return -1;
}
if (strcmp(param, "mirrordev")) {
nss_mirror_warn("Invalid param %s in mirror configure command\n", param);
return -1;
}
if (nss_mirror_ctl_get_netdev_by_name(value, &mirror_dev) < 0) {
nss_mirror_warn("Error in getting mirror net device.\n");
return -1;
}
if (nss_mirror_ctl_parse_config_param(buffer, &mirror_size,
&mirror_point, &mirror_offset)) {
dev_put(mirror_dev);
nss_mirror_warn("Error in parsing mirror configure command\n");
return -1;
}
nss_mirror_info("Mirror size: %d, mirror point: %d, mirror offset: %d\n",
mirror_size, mirror_point, mirror_offset);
if (nss_mirror_configure(mirror_dev, mirror_point,
mirror_size, mirror_offset)) {
nss_mirror_warn("Error in sending config message to %s mirror interface\n", mirror_dev->name);
dev_put(mirror_dev);
return -1;
}
dev_put(mirror_dev);
return 0;
}
/*
* nss_mirror_ctl_parse_cmd()
* API to parse mirror commands.
*/
static int32_t nss_mirror_ctl_parse_cmd(char *cmd)
{
if (cmd == NULL) {
return NSS_MIRROR_CMD_UNKNOWN;
}
if (!strcmp(cmd, "create")) {
return NSS_MIRROR_CMD_CREATE;
}
if (!strcmp(cmd, "configure")) {
return NSS_MIRROR_CMD_CONFIGURE;
}
if (!strcmp(cmd, "enable")) {
return NSS_MIRROR_CMD_ENABLE;
}
if (!strcmp(cmd, "disable")) {
return NSS_MIRROR_CMD_DISABLE;
}
if (!strcmp(cmd, "display")) {
return NSS_MIRROR_CMD_DISPLAY;
}
if (!strcmp(cmd, "destroy")) {
return NSS_MIRROR_CMD_DESTROY;
}
if (!strcmp(cmd, "set_nexthop")) {
return NSS_MIRROR_CMD_SET_NEXTHOP;
}
if (!strcmp(cmd, "reset_nexthop")) {
return NSS_MIRROR_CMD_RESET_NEXTHOP;
}
if (!strcmp(cmd, "ingress_pmc_enable")) {
return NSS_MIRROR_CMD_INGRESS_PMC_ENABLE;
}
if (!strcmp(cmd, "ingress_pmc_disable")) {
return NSS_MIRROR_CMD_INGRESS_PMC_DISABLE;
}
if (!strcmp(cmd, "help")) {
return NSS_MIRROR_CMD_HELP;
}
nss_mirror_warn("Invalid string:%s in command\n", cmd);
return NSS_MIRROR_CMD_UNKNOWN;
}
/*
* nss_mirror_ctl_config_handler()
* Mirror sysctl config handler.
*/
static int nss_mirror_ctl_config_handler(struct ctl_table *ctl, int write,
void __user *buf, size_t *lenp, loff_t *ppos)
{
char *buffer, *pfree;
char * nextarg;
int command, ret;
size_t count = *lenp;
/*
* Find the string, return an error if not found
*/
ret = proc_dostring(ctl, write, buf, lenp, ppos);
if (ret || !write) {
return ret;
}
buffer = vzalloc(count + 1);
if (!buffer) {
nss_mirror_warn("%px: Dynamic allocation failed for input buffer\n", ctl);
return -ENOMEM;
}
pfree = buffer;
if (copy_from_user(buffer, buf, count)) {
vfree(pfree);
return -EFAULT;
}
nextarg = nss_mirror_ctl_read_nextarg(&buffer);
if (!nextarg) {
goto err;
}
if (nextarg[strlen(nextarg) - 1] == '\n') {
nextarg[strlen(nextarg) - 1] = '\0';
}
command = nss_mirror_ctl_parse_cmd(nextarg);
switch (command) {
case NSS_MIRROR_CMD_CREATE:
{
struct net_device *mirror_dev;
if (!(mirror_dev = nss_mirror_create())) {
nss_mirror_warn("%s Error in create cmd\n", __func__);
goto err;
}
break;
}
case NSS_MIRROR_CMD_CONFIGURE:
{
if (nss_mirror_ctl_parse_configure_cmd(buffer)) {
nss_mirror_warn("Error in parsing configure cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_SET_NEXTHOP:
{
if (nss_mirror_ctl_parse_set_nexthop_cmd(buffer)) {
nss_mirror_warn("Error in parsing promiscuous rx enable cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_RESET_NEXTHOP:
{
if (nss_mirror_ctl_parse_reset_nexthop_cmd(buffer)) {
nss_mirror_warn("Error in parsing promiscuous rx disable cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_INGRESS_PMC_ENABLE:
{
if (nss_mirror_ctl_parse_enable_ingress_pmc_cmd(buffer)) {
nss_mirror_warn("Error in parsing set nexthop cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_INGRESS_PMC_DISABLE:
{
if (nss_mirror_ctl_parse_disable_ingress_pmc_cmd(buffer)) {
nss_mirror_warn("Error in parsing reset nexthop cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_DISABLE:
{
if (nss_mirror_ctl_parse_disable_cmd(buffer)) {
nss_mirror_warn("Error in parsing disable cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_ENABLE:
{
if (nss_mirror_ctl_parse_enable_cmd(buffer)) {
nss_mirror_warn("Error in parsing enable cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_DISPLAY:
{
if (nss_mirror_ctl_parse_display_cmd(buffer)) {
nss_mirror_warn("Error in parsing display cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_DESTROY:
{
if (nss_mirror_ctl_parse_destroy_cmd(buffer)) {
nss_mirror_warn("Error in parsing destroy cmd\n");
goto err;
}
break;
}
case NSS_MIRROR_CMD_HELP:
{
nss_mirror_ctl_display_help();
break;
}
default:
nss_mirror_warn("Invalid input in command.\n");
goto err;
}
vfree(pfree);
return ret;
err:
vfree(pfree);
return -EINVAL;
}
/*
* nss mirror sysctl table
*/
static struct ctl_table nss_mirror_table[] = {
{
.procname = "config",
.data = &nss_mirror_config_data,
.maxlen = sizeof(nss_mirror_config_data),
.mode = 0644,
.proc_handler = &nss_mirror_ctl_config_handler,
},
{ }
};
/*
* nss mirror dir
*/
static struct ctl_table nss_mirror_root_dir[] = {
{
.procname = "mirror",
.mode = 0555,
.child = nss_mirror_table,
},
{ }
};
/*
* nss mirror sysctl nss root dir
*/
static struct ctl_table nss_mirror_nss_root_dir[] = {
{
.procname = "nss",
.mode = 0555,
.child = nss_mirror_root_dir,
},
{ }
};
/*
* nss mirror sysctl root dir
*/
static struct ctl_table nss_mirror_root[] = {
{
.procname = "dev",
.mode = 0555,
.child = nss_mirror_nss_root_dir,
},
{ }
};
/*
* nss_mirror_ctl_register()
* Register command line interface for mirror.
*/
int nss_mirror_ctl_register(void)
{
nss_mirror_ctl_header = register_sysctl_table(nss_mirror_root);
if (!nss_mirror_ctl_header) {
nss_mirror_warn("Creating sysctl directory table header for mirror failed\n");
return -1;
}
return 0;
}
/*
* nss_mirror_ctl_unregister()
* Un-register command line interface for mirror.
*/
void nss_mirror_ctl_unregister(void)
{
if (nss_mirror_ctl_header) {
unregister_sysctl_table(nss_mirror_ctl_header);
}
}