svn commit: r222900 - in head/tools/tools: . cxgbetool
Navdeep Parhar
np at FreeBSD.org
Thu Jun 9 20:21:46 UTC 2011
Author: np
Date: Thu Jun 9 20:21:45 2011
New Revision: 222900
URL: http://svn.freebsd.org/changeset/base/222900
Log:
cxgbetool: a tool for the cxgbe(4) driver.
Added:
head/tools/tools/cxgbetool/
head/tools/tools/cxgbetool/Makefile (contents, props changed)
head/tools/tools/cxgbetool/cxgbetool.c (contents, props changed)
head/tools/tools/cxgbetool/reg_defs_t4.c (contents, props changed)
head/tools/tools/cxgbetool/reg_defs_t4vf.c (contents, props changed)
Modified:
head/tools/tools/README
Modified: head/tools/tools/README
==============================================================================
--- head/tools/tools/README Thu Jun 9 19:52:28 2011 (r222899)
+++ head/tools/tools/README Thu Jun 9 20:21:45 2011 (r222900)
@@ -16,6 +16,7 @@ cfi Common Flash Interface (CFI) tool
commitsdb A tool for reconstructing commit history using md5
checksums of the commit logs.
crypto Test and exercise tools related to the crypto framework
+cxgbetool A tool for the cxgbe(4) driver.
diffburst OBSOLETE: equivalent functionality is available via split -p.
For example: "split -p ^diff < patchfile". See split(1).
editing Editor modes and the like to help editing FreeBSD code.
Added: head/tools/tools/cxgbetool/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/tools/tools/cxgbetool/Makefile Thu Jun 9 20:21:45 2011 (r222900)
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= cxgbetool
+SRCS= cxgbetool.c
+NO_MAN=
+CFLAGS+= -I${.CURDIR}/../../../sys/dev/cxgbe -I.
+BINDIR?= /usr/sbin
+
+.include <bsd.prog.mk>
Added: head/tools/tools/cxgbetool/cxgbetool.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/tools/tools/cxgbetool/cxgbetool.c Thu Jun 9 20:21:45 2011 (r222900)
@@ -0,0 +1,1218 @@
+/*-
+ * Copyright (c) 2011 Chelsio Communications, Inc.
+ * All rights reserved.
+ * Written by: Navdeep Parhar <np at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "t4_ioctl.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const char *progname, *nexus;
+
+struct reg_info {
+ const char *name;
+ uint32_t addr;
+ uint32_t len;
+};
+
+struct mod_regs {
+ const char *name;
+ const struct reg_info *ri;
+};
+
+#include "reg_defs_t4.c"
+#include "reg_defs_t4vf.c"
+
+static void
+usage(FILE *fp)
+{
+ fprintf(fp, "Usage: %s <nexus> [operation]\n", progname);
+ fprintf(fp,
+ "\tfilter <idx> [<param> <val>] ... set a filter\n"
+ "\tfilter <idx> delete|clear delete a filter\n"
+ "\tfilter list list all filters\n"
+ "\tfilter mode [<match>] ... get/set global filter mode\n"
+ "\treg <address>[=<val>] read/write register\n"
+ "\treg64 <address>[=<val>] read/write 64 bit register\n"
+ "\tregdump [<module>] ... dump registers\n"
+ "\tstdio interactive mode\n"
+ );
+}
+
+static inline unsigned int
+get_card_vers(unsigned int version)
+{
+ return (version & 0x3ff);
+}
+
+static int
+real_doit(unsigned long cmd, void *data, const char *cmdstr)
+{
+ static int fd = -1;
+ int rc = 0;
+
+ if (fd == -1) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "/dev/%s", nexus);
+ if ((fd = open(buf, O_RDWR)) < 0) {
+ warn("open(%s)", nexus);
+ rc = errno;
+ return (rc);
+ }
+ }
+
+ rc = ioctl(fd, cmd, data);
+ if (rc < 0) {
+ warn("%s", cmdstr);
+ rc = errno;
+ }
+
+ return (rc);
+}
+#define doit(x, y) real_doit(x, y, #x)
+
+static char *
+str_to_number(const char *s, long *val, long long *vall)
+{
+ char *p;
+
+ if (vall)
+ *vall = strtoll(s, &p, 0);
+ else if (val)
+ *val = strtol(s, &p, 0);
+ else
+ p = NULL;
+
+ return (p);
+}
+
+static int
+read_reg(long addr, int size, long long *val)
+{
+ struct t4_reg reg;
+ int rc;
+
+ reg.addr = (uint32_t) addr;
+ reg.size = (uint32_t) size;
+ reg.val = 0;
+
+ rc = doit(CHELSIO_T4_GETREG, ®);
+
+ *val = reg.val;
+
+ return (rc);
+}
+
+static int
+write_reg(long addr, int size, long long val)
+{
+ struct t4_reg reg;
+
+ reg.addr = (uint32_t) addr;
+ reg.size = (uint32_t) size;
+ reg.val = (uint64_t) val;
+
+ return doit(CHELSIO_T4_SETREG, ®);
+}
+
+static int
+register_io(int argc, const char *argv[], int size)
+{
+ char *p, *v;
+ long addr;
+ long long val;
+ int w = 0, rc;
+
+ if (argc == 1) {
+ /* <reg> OR <reg>=<value> */
+
+ p = str_to_number(argv[0], &addr, NULL);
+ if (*p) {
+ if (*p != '=') {
+ warnx("invalid register \"%s\"", argv[0]);
+ return (EINVAL);
+ }
+
+ w = 1;
+ v = p + 1;
+ p = str_to_number(v, NULL, &val);
+
+ if (*p) {
+ warnx("invalid value \"%s\"", v);
+ return (EINVAL);
+ }
+ }
+
+ } else if (argc == 2) {
+ /* <reg> <value> */
+
+ w = 1;
+
+ p = str_to_number(argv[0], &addr, NULL);
+ if (*p) {
+ warnx("invalid register \"%s\"", argv[0]);
+ return (EINVAL);
+ }
+
+ p = str_to_number(argv[1], NULL, &val);
+ if (*p) {
+ warnx("invalid value \"%s\"", argv[1]);
+ return (EINVAL);
+ }
+ } else {
+ warnx("reg: invalid number of arguments (%d)", argc);
+ return (EINVAL);
+ }
+
+ if (w)
+ rc = write_reg(addr, size, val);
+ else {
+ rc = read_reg(addr, size, &val);
+ if (rc == 0)
+ printf("0x%llx [%llu]\n", val, val);
+ }
+
+ return (rc);
+}
+
+static inline uint32_t
+xtract(uint32_t val, int shift, int len)
+{
+ return (val >> shift) & ((1 << len) - 1);
+}
+
+static int
+dump_block_regs(const struct reg_info *reg_array, const uint32_t *regs)
+{
+ uint32_t reg_val = 0;
+
+ for ( ; reg_array->name; ++reg_array)
+ if (!reg_array->len) {
+ reg_val = regs[reg_array->addr / 4];
+ printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr,
+ reg_array->name, reg_val, reg_val);
+ } else {
+ uint32_t v = xtract(reg_val, reg_array->addr,
+ reg_array->len);
+
+ printf(" %*u:%u %-47s %#-10x %u\n",
+ reg_array->addr < 10 ? 3 : 2,
+ reg_array->addr + reg_array->len - 1,
+ reg_array->addr, reg_array->name, v, v);
+ }
+
+ return (1);
+}
+
+static int
+dump_regs_table(int argc, const char *argv[], const uint32_t *regs,
+ const struct mod_regs *modtab, int nmodules)
+{
+ int i, j, match;
+
+ for (i = 0; i < argc; i++) {
+ for (j = 0; j < nmodules; j++) {
+ if (!strcmp(argv[i], modtab[j].name))
+ break;
+ }
+
+ if (j == nmodules) {
+ warnx("invalid register block \"%s\"", argv[i]);
+ fprintf(stderr, "\nAvailable blocks:");
+ for ( ; nmodules; nmodules--, modtab++)
+ fprintf(stderr, " %s", modtab->name);
+ fprintf(stderr, "\n");
+ return (EINVAL);
+ }
+ }
+
+ for ( ; nmodules; nmodules--, modtab++) {
+
+ match = argc == 0 ? 1 : 0;
+ for (i = 0; !match && i < argc; i++) {
+ if (!strcmp(argv[i], modtab->name))
+ match = 1;
+ }
+
+ if (match)
+ dump_block_regs(modtab->ri, regs);
+ }
+
+ return (0);
+}
+
+#define T4_MODREGS(name) { #name, t4_##name##_regs }
+static int
+dump_regs_t4(int argc, const char *argv[], const uint32_t *regs)
+{
+ static struct mod_regs t4_mod[] = {
+ T4_MODREGS(sge),
+ { "pci", t4_pcie_regs },
+ T4_MODREGS(dbg),
+ T4_MODREGS(mc),
+ T4_MODREGS(ma),
+ { "edc0", t4_edc_0_regs },
+ { "edc1", t4_edc_1_regs },
+ T4_MODREGS(cim),
+ T4_MODREGS(tp),
+ T4_MODREGS(ulp_rx),
+ T4_MODREGS(ulp_tx),
+ { "pmrx", t4_pm_rx_regs },
+ { "pmtx", t4_pm_tx_regs },
+ T4_MODREGS(mps),
+ { "cplsw", t4_cpl_switch_regs },
+ T4_MODREGS(smb),
+ { "i2c", t4_i2cm_regs },
+ T4_MODREGS(mi),
+ T4_MODREGS(uart),
+ T4_MODREGS(pmu),
+ T4_MODREGS(sf),
+ T4_MODREGS(pl),
+ T4_MODREGS(le),
+ T4_MODREGS(ncsi),
+ T4_MODREGS(xgmac)
+ };
+
+ return dump_regs_table(argc, argv, regs, t4_mod, ARRAY_SIZE(t4_mod));
+}
+#undef T4_MODREGS
+
+static int
+dump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs)
+{
+ static struct mod_regs t4vf_mod[] = {
+ { "sge", t4vf_sge_regs },
+ { "mps", t4vf_mps_regs },
+ { "pl", t4vf_pl_regs },
+ { "mbdata", t4vf_mbdata_regs },
+ { "cim", t4vf_cim_regs },
+ };
+
+ return dump_regs_table(argc, argv, regs, t4vf_mod,
+ ARRAY_SIZE(t4vf_mod));
+}
+
+static int
+dump_regs(int argc, const char *argv[])
+{
+ int vers, revision, is_pcie, rc;
+ struct t4_regdump regs;
+
+ regs.data = calloc(1, T4_REGDUMP_SIZE);
+ if (regs.data == NULL) {
+ warnc(ENOMEM, "regdump");
+ return (ENOMEM);
+ }
+
+ regs.len = T4_REGDUMP_SIZE;
+ rc = doit(CHELSIO_T4_REGDUMP, ®s);
+ if (rc != 0)
+ return (rc);
+
+ vers = get_card_vers(regs.version);
+ revision = (regs.version >> 10) & 0x3f;
+ is_pcie = (regs.version & 0x80000000) != 0;
+
+ if (vers == 4) {
+ if (revision == 0x3f)
+ rc = dump_regs_t4vf(argc, argv, regs.data);
+ else
+ rc = dump_regs_t4(argc, argv, regs.data);
+ } else {
+ warnx("%s (type %d, rev %d) is not a T4 card.",
+ nexus, vers, revision);
+ return (ENOTSUP);
+ }
+
+ free(regs.data);
+ return (rc);
+}
+
+static void
+do_show_info_header(uint32_t mode)
+{
+ uint32_t i;
+
+ printf ("%4s %8s", "Idx", "Hits");
+ for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) {
+ switch (mode & i) {
+ case T4_FILTER_FCoE:
+ printf (" FCoE");
+ break;
+
+ case T4_FILTER_PORT:
+ printf (" Port");
+ break;
+
+ case T4_FILTER_OVLAN:
+ printf (" vld:oVLAN");
+ break;
+
+ case T4_FILTER_IVLAN:
+ printf (" vld:iVLAN");
+ break;
+
+ case T4_FILTER_IP_TOS:
+ printf (" TOS");
+ break;
+
+ case T4_FILTER_IP_PROTO:
+ printf (" Prot");
+ break;
+
+ case T4_FILTER_ETH_TYPE:
+ printf (" EthType");
+ break;
+
+ case T4_FILTER_MAC_IDX:
+ printf (" MACIdx");
+ break;
+
+ case T4_FILTER_MPS_HIT_TYPE:
+ printf (" MPS");
+ break;
+
+ case T4_FILTER_IP_FRAGMENT:
+ printf (" Frag");
+ break;
+
+ default:
+ /* compressed filter field not enabled */
+ break;
+ }
+ }
+ printf(" %20s %20s %9s %9s %s\n",
+ "DIP", "SIP", "DPORT", "SPORT", "Action");
+}
+
+/*
+ * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] }
+ * ordered tuple. If the parameter name in the argument sub-vector does not
+ * match the passed in parameter name, then a zero is returned for the
+ * function and no parsing is performed. If there is a match, then the value
+ * and optional mask are parsed and returned in the provided return value
+ * pointers. If no optional mask is specified, then a default mask of all 1s
+ * will be returned.
+ *
+ * An error in parsing the value[:mask] will result in an error message and
+ * program termination.
+ */
+static int
+parse_val_mask(const char *param, const char *args[], uint32_t *val,
+ uint32_t *mask)
+{
+ char *p;
+
+ if (strcmp(param, args[0]) != 0)
+ return (EINVAL);
+
+ *val = strtoul(args[1], &p, 0);
+ if (p > args[1]) {
+ if (p[0] == 0) {
+ *mask = ~0;
+ return (0);
+ }
+
+ if (p[0] == ':' && p[1] != 0) {
+ *mask = strtoul(p+1, &p, 0);
+ if (p[0] == 0)
+ return (0);
+ }
+ }
+
+ warnx("parameter \"%s\" has bad \"value[:mask]\" %s",
+ args[0], args[1]);
+
+ return (EINVAL);
+}
+
+/*
+ * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] }
+ * ordered tuple. If the parameter name in the argument sub-vector does not
+ * match the passed in parameter name, then a zero is returned for the
+ * function and no parsing is performed. If there is a match, then the value
+ * and optional mask are parsed and returned in the provided return value
+ * pointers. If no optional mask is specified, then a default mask of all 1s
+ * will be returned.
+ *
+ * The value return parameter "afp" is used to specify the expected address
+ * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual
+ * format. A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6
+ * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and
+ * AF_INET6 means that only IPv6 are acceptable. AF_INET is returned for IPv4
+ * and AF_INET6 for IPv6 addresses, respectively. IPv4 address/mask pairs are
+ * returned in the first four bytes of the address and mask return values with
+ * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0,
+ * 1, 2, 3}, respectively.
+ *
+ * An error in parsing the value[:mask] will result in an error message and
+ * program termination.
+ */
+static int
+parse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[],
+ uint8_t mask[])
+{
+ const char *colon, *afn;
+ char *slash;
+ uint8_t *m;
+ int af, ret;
+ unsigned int masksize;
+
+ /*
+ * Is this our parameter?
+ */
+ if (strcmp(param, args[0]) != 0)
+ return (EINVAL);
+
+ /*
+ * Fundamental IPv4 versus IPv6 selection.
+ */
+ colon = strchr(args[1], ':');
+ if (!colon) {
+ afn = "IPv4";
+ af = AF_INET;
+ masksize = 32;
+ } else {
+ afn = "IPv6";
+ af = AF_INET6;
+ masksize = 128;
+ }
+ if (*afp == AF_UNSPEC)
+ *afp = af;
+ else if (*afp != af) {
+ warnx("address %s is not of expected family %s",
+ args[1], *afp == AF_INET ? "IP" : "IPv6");
+ return (EINVAL);
+ }
+
+ /*
+ * Parse address (temporarily stripping off any "/mask"
+ * specification).
+ */
+ slash = strchr(args[1], '/');
+ if (slash)
+ *slash = 0;
+ ret = inet_pton(af, args[1], addr);
+ if (slash)
+ *slash = '/';
+ if (ret <= 0) {
+ warnx("Cannot parse %s %s address %s", param, afn, args[1]);
+ return (EINVAL);
+ }
+
+ /*
+ * Parse optional mask specification.
+ */
+ if (slash) {
+ char *p;
+ unsigned int prefix = strtoul(slash + 1, &p, 10);
+
+ if (p == slash + 1) {
+ warnx("missing address prefix for %s", param);
+ return (EINVAL);
+ }
+ if (*p) {
+ warnx("%s is not a valid address prefix", slash + 1);
+ return (EINVAL);
+ }
+ if (prefix > masksize) {
+ warnx("prefix %u is too long for an %s address",
+ prefix, afn);
+ return (EINVAL);
+ }
+ memset(mask, 0, masksize / 8);
+ masksize = prefix;
+ }
+
+ /*
+ * Fill in mask.
+ */
+ for (m = mask; masksize >= 8; m++, masksize -= 8)
+ *m = ~0;
+ if (masksize)
+ *m = ~0 << (8 - masksize);
+
+ return (0);
+}
+
+/*
+ * Parse an argument sub-vector as a { <parameter name> <value> } ordered
+ * tuple. If the parameter name in the argument sub-vector does not match the
+ * passed in parameter name, then a zero is returned for the function and no
+ * parsing is performed. If there is a match, then the value is parsed and
+ * returned in the provided return value pointer.
+ */
+static int
+parse_val(const char *param, const char *args[], uint32_t *val)
+{
+ char *p;
+
+ if (strcmp(param, args[0]) != 0)
+ return (EINVAL);
+
+ *val = strtoul(args[1], &p, 0);
+ if (p > args[1] && p[0] == 0)
+ return (0);
+
+ warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]);
+ return (EINVAL);
+}
+
+static void
+filters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm)
+{
+ int noctets, octet;
+
+ printf(" ");
+ if (type == 0) {
+ noctets = 4;
+ printf("%3s", " ");
+ } else
+ noctets = 16;
+
+ for (octet = 0; octet < noctets; octet++)
+ printf("%02x", addr[octet]);
+ printf("/");
+ for (octet = 0; octet < noctets; octet++)
+ printf("%02x", addrm[octet]);
+}
+
+static void
+do_show_one_filter_info(struct t4_filter *t, uint32_t mode)
+{
+ uint32_t i;
+
+ printf("%4d", t->idx);
+ if (t->hits == UINT64_MAX)
+ printf(" %8s", "-");
+ else
+ printf(" %8ju", t->hits);
+
+ /*
+ * Compressed header portion of filter.
+ */
+ for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) {
+ switch (mode & i) {
+ case T4_FILTER_FCoE:
+ printf(" %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe);
+ break;
+
+ case T4_FILTER_PORT:
+ printf(" %1d/%1d", t->fs.val.iport, t->fs.mask.iport);
+ break;
+
+ case T4_FILTER_OVLAN:
+ printf(" %1d:%1x:%02x/%1d:%1x:%02x",
+ t->fs.val.ovlan_vld, (t->fs.val.ovlan >> 7) & 0x7,
+ t->fs.val.ovlan & 0x7f, t->fs.mask.ovlan_vld,
+ (t->fs.mask.ovlan >> 7) & 0x7,
+ t->fs.mask.ovlan & 0x7f);
+ break;
+
+ case T4_FILTER_IVLAN:
+ printf(" %1d:%04x/%1d:%04x",
+ t->fs.val.ivlan_vld, t->fs.val.ivlan,
+ t->fs.mask.ivlan_vld, t->fs.mask.ivlan);
+ break;
+
+ case T4_FILTER_IP_TOS:
+ printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos);
+ break;
+
+ case T4_FILTER_IP_PROTO:
+ printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto);
+ break;
+
+ case T4_FILTER_ETH_TYPE:
+ printf(" %04x/%04x", t->fs.val.ethtype,
+ t->fs.mask.ethtype);
+ break;
+
+ case T4_FILTER_MAC_IDX:
+ printf(" %03x/%03x", t->fs.val.macidx,
+ t->fs.mask.macidx);
+ break;
+
+ case T4_FILTER_MPS_HIT_TYPE:
+ printf(" %1x/%1x", t->fs.val.matchtype,
+ t->fs.mask.matchtype);
+ break;
+
+ case T4_FILTER_IP_FRAGMENT:
+ printf(" %1d/%1d", t->fs.val.frag, t->fs.mask.frag);
+ break;
+
+ default:
+ /* compressed filter field not enabled */
+ break;
+ }
+ }
+
+ /*
+ * Fixed portion of filter.
+ */
+ filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip);
+ filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip);
+ printf(" %04x/%04x %04x/%04x",
+ t->fs.val.dport, t->fs.mask.dport,
+ t->fs.val.sport, t->fs.mask.sport);
+
+ /*
+ * Variable length filter action.
+ */
+ if (t->fs.action == FILTER_DROP)
+ printf(" Drop");
+ else if (t->fs.action == FILTER_SWITCH) {
+ printf(" Switch: port=%d", t->fs.eport);
+ if (t->fs.newdmac)
+ printf(
+ ", dmac=%02x:%02x:%02x:%02x:%02x:%02x "
+ ", l2tidx=%d",
+ t->fs.dmac[0], t->fs.dmac[1],
+ t->fs.dmac[2], t->fs.dmac[3],
+ t->fs.dmac[4], t->fs.dmac[5],
+ t->l2tidx);
+ if (t->fs.newsmac)
+ printf(
+ ", smac=%02x:%02x:%02x:%02x:%02x:%02x "
+ ", smtidx=%d",
+ t->fs.smac[0], t->fs.smac[1],
+ t->fs.smac[2], t->fs.smac[3],
+ t->fs.smac[4], t->fs.smac[5],
+ t->smtidx);
+ if (t->fs.newvlan == VLAN_REMOVE)
+ printf(", vlan=none");
+ else if (t->fs.newvlan == VLAN_INSERT)
+ printf(", vlan=insert(%x)", t->fs.vlan);
+ else if (t->fs.newvlan == VLAN_REWRITE)
+ printf(", vlan=rewrite(%x)", t->fs.vlan);
+ } else {
+ printf(" Pass: Q=");
+ if (t->fs.dirsteer == 0) {
+ printf("RSS");
+ if (t->fs.maskhash)
+ printf("(TCB=hash)");
+ } else {
+ printf("%d", t->fs.iq);
+ if (t->fs.dirsteerhash == 0)
+ printf("(QID)");
+ else
+ printf("(hash)");
+ }
+ }
+ if (t->fs.prio)
+ printf(" Prio");
+ if (t->fs.rpttid)
+ printf(" RptTID");
+ printf("\n");
+}
+
+static int
+show_filters(void)
+{
+ uint32_t mode = 0, header = 0;
+ struct t4_filter t;
+ int rc;
+
+ /* Get the global filter mode first */
+ rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode);
+ if (rc != 0)
+ return (rc);
+
+ t.idx = 0;
+ for (t.idx = 0; ; t.idx++) {
+ rc = doit(CHELSIO_T4_GET_FILTER, &t);
+ if (rc != 0 || t.idx == 0xffffffff)
+ break;
+
+ if (!header) {
+ do_show_info_header(mode);
+ header = 1;
+ }
+ do_show_one_filter_info(&t, mode);
+ };
+
+ return (rc);
+}
+
+static int
+get_filter_mode(void)
+{
+ uint32_t mode = 0;
+ int rc;
+
+ rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode);
+ if (rc != 0)
+ return (rc);
+
+ if (mode & T4_FILTER_IPv4)
+ printf("ipv4 ");
+
+ if (mode & T4_FILTER_IPv6)
+ printf("ipv6 ");
+
+ if (mode & T4_FILTER_IP_SADDR)
+ printf("sip ");
+
+ if (mode & T4_FILTER_IP_DADDR)
+ printf("dip ");
+
+ if (mode & T4_FILTER_IP_SPORT)
+ printf("sport ");
+
+ if (mode & T4_FILTER_IP_DPORT)
+ printf("dport ");
+
+ if (mode & T4_FILTER_MPS_HIT_TYPE)
+ printf("matchtype ");
+
+ if (mode & T4_FILTER_MAC_IDX)
+ printf("macidx ");
+
+ if (mode & T4_FILTER_ETH_TYPE)
+ printf("ethtype ");
+
+ if (mode & T4_FILTER_IP_PROTO)
+ printf("proto ");
+
+ if (mode & T4_FILTER_IP_TOS)
+ printf("tos ");
+
+ if (mode & T4_FILTER_IVLAN)
+ printf("ivlan ");
+
+ if (mode & T4_FILTER_OVLAN)
+ printf("ovlan ");
+
+ if (mode & T4_FILTER_PORT)
+ printf("iport ");
+
+ if (mode & T4_FILTER_FCoE)
+ printf("fcoe ");
+
+ printf("\n");
+
+ return (0);
+}
+
+static int
+set_filter_mode(int argc, const char *argv[])
+{
+ uint32_t mode = 0;
+
+ for (; argc; argc--, argv++) {
+ if (!strcmp(argv[0], "matchtype"))
+ mode |= T4_FILTER_MPS_HIT_TYPE;
+
+ if (!strcmp(argv[0], "macidx"))
+ mode |= T4_FILTER_MAC_IDX;
+
+ if (!strcmp(argv[0], "ethtype"))
+ mode |= T4_FILTER_ETH_TYPE;
+
+ if (!strcmp(argv[0], "proto"))
+ mode |= T4_FILTER_IP_PROTO;
+
+ if (!strcmp(argv[0], "tos"))
+ mode |= T4_FILTER_IP_TOS;
+
+ if (!strcmp(argv[0], "ivlan"))
+ mode |= T4_FILTER_IVLAN;
+
+ if (!strcmp(argv[0], "ovlan"))
+ mode |= T4_FILTER_OVLAN;
+
+ if (!strcmp(argv[0], "iport"))
+ mode |= T4_FILTER_PORT;
+
+ if (!strcmp(argv[0], "fcoe"))
+ mode |= T4_FILTER_FCoE;
+ }
+
+ return doit(CHELSIO_T4_SET_FILTER_MODE, &mode);
+}
+
+static int
+del_filter(uint32_t idx)
+{
+ struct t4_filter t;
+
+ t.idx = idx;
+
+ return doit(CHELSIO_T4_DEL_FILTER, &t);
+}
+
+static int
+set_filter(uint32_t idx, int argc, const char *argv[])
+{
+ int af = AF_UNSPEC, start_arg = 0;
+ struct t4_filter t;
+
+ if (argc < 2) {
+ warnc(EINVAL, "%s", __func__);
+ return (EINVAL);
+ };
+ bzero(&t, sizeof (t));
+ t.idx = idx;
+
+ for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) {
+ const char **args = &argv[start_arg];
+ uint32_t val, mask;
+
+ if (!strcmp(argv[start_arg], "type")) {
+ int newaf;
+ if (!strcasecmp(argv[start_arg + 1], "ipv4"))
+ newaf = AF_INET;
+ else if (!strcasecmp(argv[start_arg + 1], "ipv6"))
+ newaf = AF_INET6;
+ else {
+ warnx("invalid type \"%s\"; "
+ "must be one of \"ipv4\" or \"ipv6\"",
+ argv[start_arg + 1]);
+ return (EINVAL);
+ }
+
+ if (af != AF_UNSPEC && af != newaf) {
+ warnx("conflicting IPv4/IPv6 specifications.");
+ return (EINVAL);
+ }
+ af = newaf;
+ } else if (!parse_val_mask("fcoe", args, &val, &mask)) {
+ t.fs.val.fcoe = val;
+ t.fs.mask.fcoe = mask;
+ } else if (!parse_val_mask("iport", args, &val, &mask)) {
+ t.fs.val.iport = val;
+ t.fs.mask.iport = mask;
+ } else if (!parse_val_mask("ovlan", args, &val, &mask)) {
+ t.fs.val.ovlan = val;
+ t.fs.mask.ovlan = mask;
+ t.fs.val.ovlan_vld = 1;
+ t.fs.mask.ovlan_vld = 1;
+ } else if (!parse_val_mask("ivlan", args, &val, &mask)) {
+ t.fs.val.ivlan = val;
+ t.fs.mask.ivlan = mask;
+ t.fs.val.ivlan_vld = 1;
+ t.fs.mask.ivlan_vld = 1;
+ } else if (!parse_val_mask("tos", args, &val, &mask)) {
+ t.fs.val.tos = val;
+ t.fs.mask.tos = mask;
+ } else if (!parse_val_mask("proto", args, &val, &mask)) {
+ t.fs.val.proto = val;
+ t.fs.mask.proto = mask;
+ } else if (!parse_val_mask("ethtype", args, &val, &mask)) {
+ t.fs.val.ethtype = val;
+ t.fs.mask.ethtype = mask;
+ } else if (!parse_val_mask("macidx", args, &val, &mask)) {
+ t.fs.val.macidx = val;
+ t.fs.mask.macidx = mask;
+ } else if (!parse_val_mask("matchtype", args, &val, &mask)) {
+ t.fs.val.matchtype = val;
+ t.fs.mask.matchtype = mask;
+ } else if (!parse_val_mask("frag", args, &val, &mask)) {
+ t.fs.val.frag = val;
+ t.fs.mask.frag = mask;
+ } else if (!parse_val_mask("dport", args, &val, &mask)) {
+ t.fs.val.dport = val;
+ t.fs.mask.dport = mask;
+ } else if (!parse_val_mask("sport", args, &val, &mask)) {
+ t.fs.val.sport = val;
+ t.fs.mask.sport = mask;
+ } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip,
+ t.fs.mask.dip)) {
+ /* nada */;
+ } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip,
+ t.fs.mask.sip)) {
+ /* nada */;
+ } else if (!strcmp(argv[start_arg], "action")) {
+ if (!strcmp(argv[start_arg + 1], "pass"))
+ t.fs.action = FILTER_PASS;
+ else if (!strcmp(argv[start_arg + 1], "drop"))
+ t.fs.action = FILTER_DROP;
+ else if (!strcmp(argv[start_arg + 1], "switch"))
+ t.fs.action = FILTER_SWITCH;
+ else {
+ warnx("invalid action \"%s\"; must be one of"
+ " \"pass\", \"drop\" or \"switch\"",
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list