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, &reg);
+
+	*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, &reg);
+}
+
+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, &regs);
+	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