blob: cee5edcaa008dd268982aabc370e4bc0307fa444 [file] [log] [blame]
/*
*
* Copyright (C) 2007 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <net/if.h>
#include <linux/if_vlan.h>
#include <linux/sockios.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include "libcmm.h"
#include "fpp.h"
#include "cmm.h"
#include "itf.h"
#include "module_icc.h"
static void print_error(u_int32_t rc)
{
switch (rc)
{
case FPP_ERR_ICC_TOO_MANY_ENTRIES:
cmm_print(DEBUG_ERROR,"Error: Too many entries\n");
break;
case FPP_ERR_ICC_ENTRY_ALREADY_EXISTS:
cmm_print(DEBUG_ERROR,"Error: Entry already exists\n");
break;
case FPP_ERR_ICC_ENTRY_NOT_FOUND:
cmm_print(DEBUG_ERROR,"Error: Entry not found\n");
break;
case FPP_ERR_ICC_THRESHOLD_OUT_OF_RANGE:
cmm_print(DEBUG_ERROR,"Error: Threshold value out of range\n");
break;
default:
cmm_print(DEBUG_ERROR,"Error from CMM, error = `%d'\n", rc);
break;
}
}
int IccReset(daemon_handle_t daemon_handle, int argc, char *argv[])
{
cmm_command_t cmd;
cmm_response_t res;
fpp_icc_reset_cmd_t reset_cmd;
if (argc != 0)
goto usage;
memset(&cmd, 0, sizeof(cmd));
memset(&res, 0, sizeof(res));
memset(&reset_cmd, 0, sizeof(reset_cmd));
cmd.func = FPP_CMD_ICC_RESET;
cmd.length = sizeof(reset_cmd);
memcpy(&cmd.buf, &reset_cmd, sizeof(reset_cmd));
if (cmm_send(daemon_handle, &cmd, 0) != 0) {
cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (cmm_recv(daemon_handle, &res, 0) < 0) {
cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (res.rc != FPP_ERR_OK) {
print_error(res.rc);
return -1;
}
return CLI_OK;
usage:
cmm_print(DEBUG_ERROR, "Usage: icc reset\n");
return -1;
}
int IccThreshold(daemon_handle_t daemon_handle, int argc, char *argv[])
{
cmm_command_t cmd;
cmm_response_t res;
fpp_icc_threshold_cmd_t thresh_cmd;
u_int32_t val1, val2;
if (argc != 2)
goto usage;
memset(&cmd, 0, sizeof(cmd));
memset(&res, 0, sizeof(res));
memset(&thresh_cmd, 0, sizeof(thresh_cmd));
if (parse_value(argv[0], &val1, 1024) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid bmu1 threshold: %s\n", argv[0]);
goto usage;
}
if (parse_value(argv[1], &val2, 1024) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid bmu2 threshold: %s\n", argv[1]);
goto usage;
}
thresh_cmd.bmu1_threshold = val1;
thresh_cmd.bmu2_threshold = val2;
cmd.func = FPP_CMD_ICC_THRESHOLD;
cmd.length = sizeof(fpp_icc_threshold_cmd_t);
memcpy(&cmd.buf, &thresh_cmd, sizeof(thresh_cmd));
if (cmm_send(daemon_handle, &cmd, 0) != 0) {
cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (cmm_recv(daemon_handle, &res, 0) < 0) {
cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (res.rc != FPP_ERR_OK) {
print_error(res.rc);
return -1;
}
return CLI_OK;
usage:
cmm_print(DEBUG_ERROR, "Usage: icc threshold <bmu1-thresh> <bmu2-thresh>\n");
return CLI_OK;
}
static int icc_add_delete(daemon_handle_t daemon_handle, int argc, char *argv[], u_int32_t action)
{
int i;
cmm_command_t cmd;
cmm_response_t res;
fpp_icc_add_delete_cmd_t ad_cmd;
unsigned short interface;
u_int32_t val1, val2;
int arg = 2;
if (argc < 3)
goto usage;
memset(&cmd, 0, sizeof(cmd));
memset(&res, 0, sizeof(res));
memset(&ad_cmd, 0, sizeof(ad_cmd));
ad_cmd.action = action;
if (parse_icc_interface(argv[0], &interface, ICC_NUM_INTERFACES) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid interface: %s\n", argv[0]);
goto usage;
}
ad_cmd.interface = interface;
if (strcasecmp(argv[1], "ethertype") == 0)
{
if (argc != 3)
goto usage;
ad_cmd.table_type = ICC_TABLETYPE_ETHERTYPE;
if (parse_value(argv[2], &val1, 0xffff) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid ethertype: %s\n", argv[2]);
goto usage;
}
ad_cmd.ethertype.type = val1;
}
else if (strcasecmp(argv[1], "protocol") == 0)
{
ad_cmd.table_type = ICC_TABLETYPE_PROTOCOL;
while (argv[arg])
{
if (parse_range(argv[arg], &val1, &val2, 255) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid protocol: %s\n", argv[arg]);
goto usage;
}
for (i = val1; i <= val2; i++)
setbit_in_array(ad_cmd.protocol.ipproto, i, 1);
arg++;
}
}
else if (strcasecmp(argv[1], "dscp") == 0)
{
ad_cmd.table_type = ICC_TABLETYPE_DSCP;
while (argv[arg])
{
if (parse_range(argv[arg], &val1, &val2, 63) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid dscp value: %s\n", argv[arg]);
goto usage;
}
for (i = val1; i <= val2; i++)
setbit_in_array(ad_cmd.dscp.dscp_value, i, 1);
arg++;
}
}
else if (strcasecmp(argv[1], "saddr") == 0 || strcasecmp(argv[1], "daddr") == 0)
{
if (argc > 4)
goto usage;
ad_cmd.table_type = strcasecmp(argv[1], "saddr") == 0 ? ICC_TABLETYPE_SADDR : ICC_TABLETYPE_DADDR;
if (inet_pton(AF_INET, argv[2], &ad_cmd.ipaddr.v4_addr) != 1)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid IP address: %s\n", argv[2]);
goto usage;
}
if (argc == 4)
{
if (parse_value(argv[3], &val1, 32) < 0 || val1 == 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid mask length: %s\n", argv[3]);
goto usage;
}
ad_cmd.ipaddr.v4_masklen = val1;
}
else
{
ad_cmd.ipaddr.v4_masklen = 32;
}
}
else if (strcasecmp(argv[1], "saddr6") == 0 || strcasecmp(argv[1], "daddr6") == 0)
{
if (argc > 4)
goto usage;
ad_cmd.table_type = strcasecmp(argv[1], "saddr6") == 0 ? ICC_TABLETYPE_SADDR6 : ICC_TABLETYPE_DADDR6;
if (inet_pton(AF_INET6, argv[2], ad_cmd.ipv6addr.v6_addr) != 1)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid IPv6 address: %s\n", argv[2]);
goto usage;
}
if (argc == 4)
{
if (parse_value(argv[3], &val1, 128) < 0 || val1 == 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid mask length: %s\n", argv[3]);
goto usage;
}
ad_cmd.ipv6addr.v6_masklen = val1;
}
else
{
ad_cmd.ipv6addr.v6_masklen = 128;
}
}
else if (strcasecmp(argv[1], "port") == 0)
{
if (argc != 4)
goto usage;
ad_cmd.table_type = ICC_TABLETYPE_PORT;
if (parse_range(argv[2], &val1, &val2, 0xffff) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid source port: %s\n", argv[2]);
goto usage;
}
ad_cmd.port.sport_from = val1;
ad_cmd.port.sport_to = val2;
if (parse_range(argv[3], &val1, &val2, 0xffff) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid destination port: %s\n", argv[3]);
goto usage;
}
ad_cmd.port.dport_from = val1;
ad_cmd.port.dport_to = val2;
}
else if (strcasecmp(argv[1], "sport") == 0)
{
if (argc != 3)
goto usage;
ad_cmd.table_type = ICC_TABLETYPE_PORT;
if (parse_range(argv[2], &val1, &val2, 0xffff) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid source port: %s\n", argv[2]);
goto usage;
}
ad_cmd.port.sport_from = val1;
ad_cmd.port.sport_to = val2;
ad_cmd.port.dport_from = 0;
ad_cmd.port.dport_to = 65535;
}
else if (strcasecmp(argv[1], "dport") == 0)
{
if (argc != 3)
goto usage;
ad_cmd.table_type = ICC_TABLETYPE_PORT;
if (parse_range(argv[2], &val1, &val2, 0xffff) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid destination port: %s\n", argv[2]);
goto usage;
}
ad_cmd.port.dport_from = val1;
ad_cmd.port.dport_to = val2;
ad_cmd.port.sport_from = 0;
ad_cmd.port.sport_to = 65535;
}
else if (strcasecmp(argv[1], "vlan") == 0)
{
ad_cmd.table_type = ICC_TABLETYPE_VLAN;
if (argc > 4)
goto usage;
if (parse_range(argv[2], &val1, &val2, 8191) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid vlan ID: %s\n", argv[2]);
goto usage;
}
ad_cmd.vlan.vlan_from = val1;
ad_cmd.vlan.vlan_to = val2;
if (argc == 4)
{
if (parse_range(argv[3], &val1, &val2, 7) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid vlan priority: %s\n", argv[3]);
goto usage;
}
}
else
{
val1 = 0;
val2 = 7;
}
ad_cmd.vlan.prio_from = val1;
ad_cmd.vlan.prio_to = val2;
}
else
{
cmm_print(DEBUG_ERROR, "ERROR: Unknown keyword %s\n", argv[1]);
goto usage;
}
cmd.func = FPP_CMD_ICC_ADD_DELETE;
cmd.length = sizeof(fpp_icc_add_delete_cmd_t);
memcpy(&cmd.buf, &ad_cmd, sizeof(ad_cmd));
if (cmm_send(daemon_handle, &cmd, 0) != 0) {
cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (cmm_recv(daemon_handle, &res, 0) < 0) {
cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (res.rc != FPP_ERR_OK) {
print_error(res.rc);
return -1;
}
return CLI_OK;
usage:
cmm_print(DEBUG_ERROR, "Usage: icc [add | delete] <interface>\n"
"\t[\n"
"\t\t[ethertype <type>] |\n"
"\t\t[protocol <proto-1> <proto-2> ...] |\n"
"\t\t[dscp <value-1> <value-2> ...] |\n"
"\t\t[saddr <addr> [<masklen>]] |\n"
"\t\t[daddr <addr> [<masklen>]] |\n"
"\t\t[saddr6 <addr> [<masklen>]] |\n"
"\t\t[daddr6 <addr> [<masklen>]] |\n"
"\t\t[port <srcport> <dstport>] |\n"
"\t\t[sport <srcport>] |\n"
"\t\t[dport <dstport>] |\n"
"\t\t[vlan <id> [<priority>]] |\n"
"\t]\n");
return CLI_OK;
}
int IccAdd(daemon_handle_t daemon_handle, int argc, char *argv[])
{
return icc_add_delete(daemon_handle, argc, argv, ICC_ACTION_ADD);
}
int IccDelete(daemon_handle_t daemon_handle, int argc, char *argv[])
{
return icc_add_delete(daemon_handle, argc, argv, ICC_ACTION_DELETE);
}
int IccQuery(daemon_handle_t daemon_handle, int argc, char *argv[])
{
int i, j;
cmm_command_t cmd;
cmm_response_t res;
fpp_icc_query_cmd_t query_cmd;
fpp_icc_query_reply_t *prsp = (fpp_icc_query_reply_t *)&res.buf[0];
u_int16_t interface;
u_int16_t interface_from, interface_to;
u_int16_t action;
char buf[1024];
if (argc > 1)
goto usage;
memset(&cmd, 0, sizeof(cmd));
memset(&res, 0, sizeof(res));
memset(&query_cmd, 0, sizeof(query_cmd));
if (argc == 1)
{
if (parse_icc_interface(argv[0], &interface_from, ICC_NUM_INTERFACES) < 0)
{
cmm_print(DEBUG_ERROR, "ERROR: Invalid interface: %s\n", argv[0]);
goto usage;
}
interface_to = interface_from;
}
else
{
interface_from = 0;
interface_to = ICC_NUM_INTERFACES - 1;
}
for (interface = interface_from; interface <= interface_to; interface++)
{
cmm_print(DEBUG_STDOUT, "ICC interface %d --\n", interface);
cmd.func = FPP_CMD_ICC_QUERY;
cmd.length = sizeof(fpp_icc_query_cmd_t);
action = ICC_ACTION_QUERY;
while (1)
{
query_cmd.action = action;
query_cmd.interface = interface;
memcpy(&cmd.buf, &query_cmd, sizeof(query_cmd));
if (cmm_send(daemon_handle, &cmd, 0) != 0) {
cmm_print(DEBUG_ERROR, "Error sending message to CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (cmm_recv(daemon_handle, &res, 0) < 0) {
cmm_print(DEBUG_ERROR, "Error receiving message from CMM, error = `%s'\n", strerror(errno));
return -1;
}
if (prsp->query_result != 0 || prsp->interface != interface)
break;
switch (prsp->table_type)
{
case ICC_TABLETYPE_ETHERTYPE:
{
cmm_print(DEBUG_STDOUT, "Ethertype: 0x%04x\n", prsp->ethertype.type);
break;
}
case ICC_TABLETYPE_PROTOCOL:
{
buf[0] = '\0';
for (i = 0; i < 256; i++)
{
if (!testbit_in_array(prsp->protocol.ipproto, i))
continue;
j = i + 1;
if (j == 256 || !testbit_in_array(prsp->protocol.ipproto, j))
{
sprintf(buf + strlen(buf), "%d ", i);
}
else
{
while (j < 255 && testbit_in_array(prsp->protocol.ipproto, j + 1))
j++;
sprintf(buf + strlen(buf), "%d-%d ", i, j);
}
i = j;
}
cmm_print(DEBUG_STDOUT, "Protocols: %s\n", buf);
break;
}
case ICC_TABLETYPE_DSCP:
{
buf[0] = '\0';
for (i = 0; i < 64; i++)
{
if (!testbit_in_array(prsp->dscp.dscp_value, i))
continue;
j = i + 1;
if (j == 64 || !testbit_in_array(prsp->dscp.dscp_value, j))
{
sprintf(buf + strlen(buf), "%d ", i);
}
else
{
while (j < 63 && testbit_in_array(prsp->dscp.dscp_value, j + 1))
j++;
sprintf(buf + strlen(buf), "%d-%d ", i, j);
}
i = j;
}
cmm_print(DEBUG_STDOUT, "DSCP values: %s\n", buf);
break;
}
case ICC_TABLETYPE_SADDR:
{
cmm_print(DEBUG_STDOUT, "IPv4 Source Address: %s/%d\n",
inet_ntop(AF_INET, &prsp->ipaddr.v4_addr, buf, sizeof(buf)),
prsp->ipaddr.v4_masklen);
break;
}
case ICC_TABLETYPE_DADDR:
{
cmm_print(DEBUG_STDOUT, "IPv4 Destination Address: %s/%d\n",
inet_ntop(AF_INET, &prsp->ipaddr.v4_addr, buf, sizeof(buf)),
prsp->ipaddr.v4_masklen);
break;
}
case ICC_TABLETYPE_SADDR6:
{
cmm_print(DEBUG_STDOUT, "IPv6 Source Address: %s/%d\n",
inet_ntop(AF_INET6, prsp->ipv6addr.v6_addr, buf, sizeof(buf)),
prsp->ipv6addr.v6_masklen);
break;
}
case ICC_TABLETYPE_DADDR6:
{
cmm_print(DEBUG_STDOUT, "IPv6 Destination Address: %s/%d\n",
inet_ntop(AF_INET6, prsp->ipv6addr.v6_addr, buf, sizeof(buf)),
prsp->ipv6addr.v6_masklen);
break;
}
case ICC_TABLETYPE_PORT:
{
cmm_print(DEBUG_STDOUT, "Ports: Source %d-%d / Destination %d-%d\n",
prsp->port.sport_from, prsp->port.sport_to,
prsp->port.dport_from, prsp->port.dport_to);
break;
}
case ICC_TABLETYPE_VLAN:
{
cmm_print(DEBUG_STDOUT, "VLAN: ID %d-%d / Priority %d-%d\n",
prsp->vlan.vlan_from, prsp->vlan.vlan_to,
prsp->vlan.prio_from, prsp->vlan.prio_to);
break;
}
}
action = ICC_ACTION_QUERY_CONT;
}
cmm_print(DEBUG_STDOUT, "-------------\n\n");
}
return CLI_OK;
usage:
cmm_print(DEBUG_ERROR, "Usage: icc query [<interface>]\n");
return CLI_OK;
}