summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.sbin')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/Makefile1
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/arp.c7
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ndp.c9
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/route.c90
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c30
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile7
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c12
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h3
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c13
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c9
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c557
11 files changed, 708 insertions, 30 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
index 864920184a..3f794a331a 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
@@ -157,6 +157,7 @@ route := CPPFLAGS += -DNDEBUG
ndd := LDLIBS += -ldladm -lipadm
$(RELEASE_BUILD)ndd := CERRWARN += -_gcc=-Wno-unused
in.comsat := LDFLAGS += $(MAPFILE.NGB:%=-Wl,-M%)
+route := LDLIBS += -lzonecfg -lcontract
.KEEP_STATE:
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/arp.c b/usr/src/cmd/cmd-inet/usr.sbin/arp.c
index 720b996f57..784e87ca6f 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/arp.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/arp.c
@@ -58,6 +58,7 @@
#include <arpa/inet.h>
#include <net/if_types.h>
#include <net/if_dl.h>
+#include <zone.h>
static int file(char *);
static int set(int, char *[]);
@@ -119,7 +120,11 @@ main(int argc, char *argv[])
* is to let netstat, which prints it as part of
* the MIB statistics, do it.
*/
- (void) execl("/usr/bin/netstat", "netstat",
+ char netstat_path[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+ (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
+ zroot : "", "/usr/bin/netstat");
+ (void) execl(netstat_path, "netstat",
(n_flag ? "-np" : "-p"),
"-f", "inet", (char *)0);
(void) fprintf(stderr, "failed to exec netstat: %s\n",
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ndp.c b/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
index d2c26bf0b2..c77e1587d9 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
@@ -40,6 +40,7 @@
#include <inet/ip.h>
#include <net/if_dl.h>
#include <net/route.h>
+#include <zone.h>
typedef struct sockaddr_in6 sin6_t;
@@ -95,7 +96,6 @@ static int ndp_set_nce(char *, char *, char *[], int);
static int ndp_set_file(char *);
static char *ndp_iface = NULL;
-static char *netstat_path = "/usr/bin/netstat";
static pid_t ndp_pid;
static boolean_t ndp_noresolve = B_FALSE; /* Don't lookup addresses */
static boolean_t ndp_run = B_TRUE;
@@ -103,6 +103,7 @@ static boolean_t ndp_run = B_TRUE;
#define MAX_ATTEMPTS 5
#define MAX_OPTS 5
#define WORDSEPS " \t\r\n"
+#define NETSTAT_PATH "/usr/bin/netstat"
/*
* Macros borrowed from route(8) for working with PF_ROUTE messages
@@ -767,6 +768,12 @@ ndp_get(int fd, struct lifreq *lifrp, void *unused)
static void
ndp_get_all(void)
{
+ char netstat_path[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+
+ (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
+ zroot : "", NETSTAT_PATH);
+
(void) execl(netstat_path, "netstat",
(ndp_noresolve ? "-np" : "-p"),
"-f", "inet6", (char *)0);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/route.c b/usr/src/cmd/cmd-inet/usr.sbin/route.c
index d8f11bd4a6..17a63d6f95 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/route.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c
@@ -6,6 +6,7 @@
/* All Rights Reserved */
/* Copyright (c) 1990 Mentat Inc. */
+/* Copyright 2018, Joyent, Inc. */
/*
*
@@ -79,6 +80,13 @@
#include <assert.h>
#include <strings.h>
+#include <libcontract.h>
+#include <sys/ctfs.h>
+#include <sys/contract/process.h>
+#include <sys/wait.h>
+#include <libzonecfg.h>
+#include <zone.h>
+
#include <libtsnet.h>
#include <tsol/label.h>
@@ -292,6 +300,7 @@ static void syntax_error(char *err, ...);
static void usage(char *cp);
static void write_to_rtfile(FILE *fp, int argc, char **argv);
static void pmsg_secattr(const char *, size_t, const char *);
+static void do_zone(char *);
static pid_t pid;
static int s;
@@ -308,6 +317,7 @@ static char perm_file_sfx[] = "/etc/inet/static_routes";
static char *perm_file;
static char temp_file_sfx[] = "/etc/inet/static_routes.tmp";
static char *temp_file;
+static char *zonename;
static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/*
@@ -354,7 +364,7 @@ usage(char *cp)
cp);
}
(void) fprintf(stderr, gettext("usage: route [ -fnpqv ] "
- "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n"));
+ "[-z <zone> ] [ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n"));
exit(1);
/* NOTREACHED */
}
@@ -418,7 +428,7 @@ main(int argc, char **argv)
if (argc < 2)
usage(NULL);
- while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) {
+ while ((ch = getopt(argc, argv, "R:nqdtvfpz:")) != EOF) {
switch (ch) {
case 'n':
nflag = B_TRUE;
@@ -444,6 +454,9 @@ main(int argc, char **argv)
case 'R':
root_dir = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
case '?':
default:
usage(NULL);
@@ -453,6 +466,8 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
+ do_zone(zonename);
+
pid = getpid();
if (tflag)
s = open("/dev/null", O_WRONLY);
@@ -3252,3 +3267,74 @@ pmsg_secattr(const char *sptr, size_t msglen, const char *labelstr)
sizeof (buf)));
}
}
+
+static void
+do_zone(char *name)
+{
+ zoneid_t zoneid;
+ zone_state_t st;
+ int fd, status, rc = 0;
+ pid_t pid;
+
+ if (name == NULL)
+ return;
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ (void) fprintf(stderr,
+ "route: -z can only be specified from the global zone\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(name, GLOBAL_ZONENAME) == 0)
+ return;
+
+ if (zone_get_state(name, &st) != Z_OK)
+ quit("unable to get zone state", errno);
+
+ if (st != ZONE_STATE_RUNNING) {
+ (void) fprintf(stderr, "route: zone must be running\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((zoneid = getzoneidbyname(name)) == -1)
+ quit("cannot determine zone id", errno);
+
+ if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) == -1)
+ quit("cannot open ctfs template", errno);
+
+ /*
+ * zone_enter() does not allow contracts to straddle zones, so we must
+ * create a new, though largely unused contract. Once we fork, the
+ * child is the only member of the new contract, so it can perform a
+ * zone_enter().
+ */
+ rc |= ct_tmpl_set_critical(fd, 0);
+ rc |= ct_tmpl_set_informative(fd, 0);
+ rc |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
+ rc |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
+ if (rc || ct_tmpl_activate(fd)) {
+ (void) close(fd);
+ quit("could not create contract", errno);
+ }
+
+ switch (pid = fork1()) {
+ case 0:
+ (void) ct_tmpl_clear(fd);
+ (void) close(fd);
+ if (zone_enter(zoneid) == -1)
+ quit("could not enter zone", errno);
+ return;
+
+ case -1:
+ quit("fork1 failed", errno);
+
+ default:
+ (void) ct_tmpl_clear(fd);
+ (void) close(fd);
+ if (waitpid(pid, &status, 0) < 0)
+ quit("waitpid failed", errno);
+
+ exit(WEXITSTATUS(status));
+ }
+
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
index 657fc77f9d..6fad8a3513 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
@@ -21,6 +21,7 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -44,6 +45,7 @@
#include <libscf.h>
#include <libscf_priv.h>
#include <libuutil.h>
+#include <ifaddrs.h>
/*
* This program moves routing management under SMF. We do this by giving
@@ -2333,8 +2335,8 @@ out:
/*
*
- * Return the number of IPv6 addresses configured. This answers the
- * generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
+ * Return the number of non-loopback IPv6 addresses configured. This answers
+ * the generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
* is configured, and we also only enable IPv6 routing daemons if IPv6 is
* enabled.
*/
@@ -2342,28 +2344,24 @@ static int
ra_numv6intfs(void)
{
static int num = -1;
- int ipsock;
- struct lifnum lifn;
+ int cnt;
+ struct ifaddrs *ifp_head, *ifp;
if (num != -1)
return (num);
- if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
- (void) fprintf(stderr,
- gettext("%1$s: unable to open %2$s: %3$s\n"),
- myname, IP_DEV_NAME, strerror(errno));
+ if (getifaddrs(&ifp_head) < 0)
return (0);
- }
- lifn.lifn_family = AF_INET6;
- lifn.lifn_flags = 0;
- if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
- (void) close(ipsock);
- return (0);
+ cnt = 0;
+ for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+ if (!(ifp->ifa_flags & IFF_LOOPBACK) &&
+ (ifp->ifa_flags & IFF_IPV6))
+ cnt++;
}
- (void) close(ipsock);
- return (num = lifn.lifn_count);
+ freeifaddrs(ifp_head);
+ return (num = cnt);
}
/*
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
index e026093057..4839757233 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
@@ -40,17 +40,18 @@ OBJS= nfs4_xdr.o snoop.o snoop_aarp.o snoop_adsp.o snoop_aecho.o \
snoop_pppoe.o snoop_rip.o snoop_rip6.o snoop_rpc.o snoop_rpcprint.o \
snoop_rpcsec.o snoop_rport.o snoop_rquota.o snoop_rstat.o snoop_rtmp.o \
snoop_sctp.o snoop_slp.o snoop_smb.o snoop_socks.o snoop_solarnet.o \
- snoop_tcp.o snoop_tftp.o snoop_trill.o snoop_udp.o snoop_vxlan.o \
- snoop_zip.o
+ snoop_svp.o snoop_tcp.o snoop_tftp.o snoop_trill.o snoop_udp.o \
+ snoop_vxlan.o snoop_zip.o
SRCS= $(OBJS:.o=.c)
HDRS= snoop.h snoop_mip.h at.h snoop_ospf.h snoop_ospf6.h
include ../../../Makefile.cmd
+include ../../../Makefile.ctf
CPPFLAGS += -I. -I$(SRC)/common/net/dhcp \
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl -ltsol
+LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl -ltsol -luuid
LDFLAGS += $(MAPFILE.NGB:%=-Wl,-M%)
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-implicit-function-declaration
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
index 860bb55f79..c9b1eb848e 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
@@ -124,6 +124,7 @@ main(int argc, char **argv)
char *output_area;
int nbytes;
char *datalink = NULL;
+ char *zonename = NULL;
dlpi_handle_t dh;
names[0] = '\0';
@@ -230,7 +231,7 @@ main(int argc, char **argv)
}
(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
- while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:fc:x:U?rqz"))
+ while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:fc:x:U?rqz:Z"))
!= EOF) {
switch (c) {
case 'a':
@@ -337,8 +338,11 @@ main(int argc, char **argv)
case 'U':
Uflg = B_TRUE;
break;
-#ifdef DEBUG
case 'z':
+ zonename = optarg;
+ break;
+#ifdef DEBUG
+ case 'Z':
zflg = B_TRUE;
break;
#endif /* DEBUG */
@@ -360,7 +364,7 @@ main(int argc, char **argv)
* requested was chosen, but that's too hard.
*/
if (!icapfile) {
- use_kern_pf = open_datalink(&dh, datalink);
+ use_kern_pf = open_datalink(&dh, datalink, zonename);
} else {
use_kern_pf = B_FALSE;
cap_open_read(icapfile);
@@ -801,6 +805,8 @@ usage(void)
(void) fprintf(stderr,
"\t[ -r ] # Do not resolve address to name\n");
(void) fprintf(stderr,
+ "\t[ -z zone ] # Open links from named zone\n");
+ (void) fprintf(stderr,
"\n\t[ filter expression ]\n");
(void) fprintf(stderr, "\nExample:\n");
(void) fprintf(stderr, "\tsnoop -o saved host fred\n\n");
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
index 52a496db73..19a8c25a87 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
@@ -216,7 +216,7 @@ extern void cap_open_read(const char *);
extern void cap_open_write(const char *);
extern void cap_read(int, int, int, void (*)(), int);
extern void cap_close(void);
-extern boolean_t open_datalink(dlpi_handle_t *, const char *);
+extern boolean_t open_datalink(dlpi_handle_t *, const char *, const char *);
extern void init_datalink(dlpi_handle_t, ulong_t, ulong_t, struct timeval *,
struct Pf_ext_packetfilt *);
extern void net_read(dlpi_handle_t, size_t, int, void (*)(), int);
@@ -295,6 +295,7 @@ extern int interpret_trill(int, struct ether_header **, char *, int *);
extern int interpret_isis(int, char *, int, boolean_t);
extern int interpret_bpdu(int, char *, int);
extern int interpret_vxlan(int, char *, int);
+extern int interpret_svp(int, char *, int);
extern void init_ldap(void);
extern boolean_t arp_for_ether(char *, struct ether_addr *);
extern char *ether_ouiname(uint32_t);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
index b0cc78b5f2..63eb4973a0 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
@@ -30,6 +30,7 @@
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/signal.h>
@@ -115,7 +116,7 @@ select_datalink(const char *linkname, void *arg)
* about the datalink useful for building the proper packet filters.
*/
boolean_t
-open_datalink(dlpi_handle_t *dhp, const char *linkname)
+open_datalink(dlpi_handle_t *dhp, const char *linkname, const char *zonename)
{
int retval;
int flags = DLPI_PASSIVE | DLPI_RAW;
@@ -123,6 +124,9 @@ open_datalink(dlpi_handle_t *dhp, const char *linkname)
dlpi_info_t dlinfo;
if (linkname == NULL) {
+ if (zonename != NULL)
+ pr_err("a datalink must be specified with a zone name");
+
/*
* Select a datalink to use by default. Prefer datalinks that
* are plumbed by IP.
@@ -146,7 +150,8 @@ open_datalink(dlpi_handle_t *dhp, const char *linkname)
flags |= DLPI_DEVIPNET;
if (Iflg || strcmp(linkname, "lo0") == 0)
flags |= DLPI_IPNETINFO;
- if ((retval = dlpi_open(linkname, dhp, flags)) != DLPI_SUCCESS) {
+ if ((retval = dlpi_open_zone(linkname, zonename, dhp,
+ flags)) != DLPI_SUCCESS) {
pr_err("cannot open \"%s\": %s", linkname,
dlpi_strerror(retval));
}
@@ -636,6 +641,10 @@ cap_open_read(const char *name)
if (fstat(capfile_in, &st) < 0)
pr_err("couldn't stat %s: %m", name);
+ if (st.st_size > INT_MAX)
+ pr_err("input file size (%llu bytes) exceeds maximum "
+ "supported size (%d bytes)",
+ (unsigned long long)st.st_size, INT_MAX);
cap_len = st.st_size;
cap_buffp = mmap(0, cap_len, PROT_READ, MAP_PRIVATE, capfile_in, 0);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
index 6e67d03950..77e9d97766 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
@@ -21,7 +21,7 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2018, Joyent, Inc.
*/
#include <stdio.h>
@@ -130,6 +130,7 @@ static struct porttable pt_tcp[] = {
{ 540, "UUCP" },
{ 600, "PCSERVER" },
{ IPPORT_SOCKS, "SOCKS" },
+ { 1296, "SVP" },
{ 1524, "INGRESLOCK" },
{ 2904, "M2UA" },
{ 2905, "M3UA" },
@@ -430,6 +431,12 @@ interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
case IPPORT_VXLAN:
(void) interpret_vxlan(flags, data, dlen);
return (1);
+ case 1296:
+ if (proto == IPPROTO_TCP) {
+ (void) interpret_svp(flags, data, dlen);
+ return (1);
+ }
+ break;
}
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c
new file mode 100644
index 0000000000..a0768c2234
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c
@@ -0,0 +1,557 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Decode SVP (SmartDC VxLAN Protocol) packets
+ */
+
+#include <inttypes.h>
+#include <sys/crc32.h>
+#include <uuid/uuid.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <libvarpd_svp_prot.h>
+#include "snoop.h"
+
+/*
+ * String size large enough for an IPv6 address + / + a 3 digit (or less)
+ * prefix length
+ */
+#define ADDRSTR_LEN (INET6_ADDRSTRLEN + 4)
+
+/*
+ * Large enough for all currently known status strings as well as a
+ * 16-bit hex value.
+ */
+#define STATUSSTR_LEN 32
+
+/*
+ * Large enough for all currently known op strings, as well as a
+ * 16-bit hex value.
+ */
+#define OPSTR_LEN 32
+
+/*
+ * Large enough for VL3 types and bulk types, as well as a 32-bit
+ * hex value.
+ */
+#define TYPESTR_LEN 32
+
+static uint32_t svp_crc32_tab[] = { CRC32_TABLE };
+
+#define STR(_x, _buf, _len) \
+ case _x: \
+ (void) strlcpy(_buf, #_x, _len); \
+ break
+
+static void
+svp_op_str(uint16_t op, char *buf, size_t buflen)
+{
+ switch (op) {
+ STR(SVP_R_UNKNOWN, buf, buflen);
+ STR(SVP_R_PING, buf, buflen);
+ STR(SVP_R_PONG, buf, buflen);
+ STR(SVP_R_VL2_REQ, buf, buflen);
+ STR(SVP_R_VL2_ACK, buf, buflen);
+ STR(SVP_R_VL3_REQ, buf, buflen);
+ STR(SVP_R_VL3_ACK, buf, buflen);
+ STR(SVP_R_BULK_REQ, buf, buflen);
+ STR(SVP_R_BULK_ACK, buf, buflen);
+ STR(SVP_R_LOG_REQ, buf, buflen);
+ STR(SVP_R_LOG_ACK, buf, buflen);
+ STR(SVP_R_LOG_RM, buf, buflen);
+ STR(SVP_R_LOG_RM_ACK, buf, buflen);
+ STR(SVP_R_SHOOTDOWN, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%hx", op);
+ }
+}
+
+static void
+svp_status_str(uint16_t status, char *buf, size_t buflen)
+{
+ switch (status) {
+ STR(SVP_S_OK, buf, buflen);
+ STR(SVP_S_FATAL, buf, buflen);
+ STR(SVP_S_NOTFOUND, buf, buflen);
+ STR(SVP_S_BADL3TYPE, buf, buflen);
+ STR(SVP_S_BADBULK, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%hx", status);
+ }
+}
+
+static void
+svp_vl3_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_VL3_IP, buf, buflen);
+ STR(SVP_VL3_IPV6, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+
+static void
+svp_bulk_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_BULK_VL2, buf, buflen);
+ STR(SVP_BULK_VL3, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+
+static void
+svp_log_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_LOG_VL2, buf, buflen);
+ STR(SVP_LOG_VL3, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+#undef STR
+
+static void
+svp_addr_str(void *addrp, uint8_t *prefixp, char *buf, size_t buflen)
+{
+ struct in_addr v4;
+ int af = AF_INET6;
+
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addrp)) {
+ af = AF_INET;
+ IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addrp, &v4);
+ addrp = &v4;
+ }
+
+ if (inet_ntop(af, addrp, buf, buflen) == NULL) {
+ uint8_t *p = addrp;
+ size_t i;
+
+ (void) strlcpy(buf, "0x", buflen);
+ for (i = 0; i < 16; i++) {
+ (void) snprintf(buf + 2 + i * 2,
+ sizeof (buf) - 2 - i * 2, "%02hhx", p[i]);
+ }
+ }
+
+ if (prefixp != NULL && *prefixp != 128) {
+ char buf2[5]; /* / + 3 digits + NUL */
+
+ if (af == AF_INET)
+ *prefixp -= 96;
+
+ (void) snprintf(buf2, sizeof (buf2), "/%hhu", *prefixp);
+ (void) strlcat(buf, buf2, buflen);
+ }
+}
+
+static boolean_t
+svp_check_crc(char *data, int len)
+{
+ svp_req_t *req = (svp_req_t *)data;
+ uint32_t save_crc = req->svp_crc32;
+ uint32_t crc = -1U;
+
+ req->svp_crc32 = 0;
+ CRC32(crc, (uint8_t *)data, len, -1U, svp_crc32_tab);
+ crc = ~crc;
+ req->svp_crc32 = save_crc;
+
+ return (ntohl(save_crc) == crc ? B_TRUE : B_FALSE);
+}
+
+static void
+do_svp_vl2_req(void *data, int len)
+{
+ svp_vl2_req_t *vl2 = data;
+
+ show_printf("MAC = %s", ether_ntoa((struct ether_addr *)vl2->sl2r_mac));
+ show_printf("Virtual network id = %u", ntohl(vl2->sl2r_vnetid));
+}
+
+static void
+do_svp_vl2_ack(void *data, int len)
+{
+ svp_vl2_ack_t *vl2a = data;
+ char status[STATUSSTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_status_str(ntohs(vl2a->sl2a_status), status, sizeof (status));
+ svp_addr_str(vl2a->sl2a_addr, NULL, addr, sizeof (addr));
+
+ show_printf("Status = %s", status);
+ show_printf("UL3 Address = %s", addr);
+ show_printf("UL3 Port = %hu", ntohs(vl2a->sl2a_port));
+}
+
+static void
+do_svp_vl3_req(void *data, int len)
+{
+ svp_vl3_req_t *req = data;
+ char type[TYPESTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_vl3_type_str(ntohl(req->sl3r_type), type, sizeof (type));
+ svp_addr_str(req->sl3r_ip, NULL, addr, sizeof (addr));
+
+ show_printf("Virtual network id = %u", ntohl(req->sl3r_vnetid));
+ show_printf("Type = %s", type);
+ show_printf("VL3 Address = %s", addr);
+}
+
+static void
+do_svp_vl3_ack(void *data, int len)
+{
+ svp_vl3_ack_t *vl3a = data;
+ char status[STATUSSTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_status_str(ntohl(vl3a->sl3a_status), status, sizeof (status));
+ svp_addr_str(vl3a->sl3a_uip, NULL, addr, sizeof (addr));
+
+ show_printf("Status = %s", status);
+ show_printf("MAC = %s",
+ ether_ntoa((struct ether_addr *)vl3a->sl3a_mac));
+ show_printf("UL3 Address = %s", addr);
+ show_printf("UL3 Port = %hu", ntohs(vl3a->sl3a_uport));
+}
+
+static void
+do_svp_bulk_req(void *data, int len)
+{
+ svp_bulk_req_t *req = data;
+ char type[TYPESTR_LEN];
+
+ if (len < sizeof (svp_bulk_req_t)) {
+ show_printf("SVP_R_BULK_REQ runt");
+ return;
+ }
+
+ svp_bulk_type_str(ntohl(req->svbr_type), type, sizeof (type));
+ show_printf("Type = %s", type);
+}
+
+static void
+do_svp_bulk_ack(void *data, int len)
+{
+ svp_bulk_ack_t *ack = data;
+ char status[STATUSSTR_LEN];
+ char type[TYPESTR_LEN];
+
+ svp_status_str(ntohl(ack->svba_status), status, sizeof (status));
+ svp_bulk_type_str(ntohl(ack->svba_type), type, sizeof (type));
+
+ show_printf("Status = %s", status);
+ show_printf("Type = %s", type);
+
+ /*
+ * Currently the data format is undefined (see libvarp_svp_prot.h),
+ * so there is nothing else we can display.
+ */
+}
+
+static void
+do_svp_log_req(void *data, int len)
+{
+ svp_log_req_t *svlr = data;
+ char addr[ADDRSTR_LEN];
+
+ svp_addr_str(svlr->svlr_ip, NULL, addr, sizeof (addr));
+
+ show_printf("Count = %u", ntohl(svlr->svlr_count));
+ show_printf("Address = %s", addr);
+}
+
+static void
+do_svp_log_ack(void *data, int len)
+{
+ svp_log_ack_t *ack = data;
+ union {
+ svp_log_vl2_t *vl2;
+ svp_log_vl3_t *vl3;
+ uint32_t *vtype;
+ void *vd;
+ } u;
+ size_t total = 0, rlen = 0;
+ uint8_t prefixlen;
+ boolean_t is_host;
+ char status[STATUSSTR_LEN];
+ char typestr[TYPESTR_LEN];
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+ char addr[ADDRSTR_LEN];
+
+ u.vd = (ack + 1);
+
+ svp_status_str(ntohl(ack->svla_status), status, sizeof (status));
+
+ show_printf("Status = %s", status);
+ len -= sizeof (*ack);
+
+ while (len > 0) {
+ uint32_t type;
+
+ if (len < sizeof (uint32_t)) {
+ show_printf(" Trailing runt");
+ break;
+ }
+
+ type = ntohl(*u.vtype);
+ svp_log_type_str(type, typestr, sizeof (typestr));
+
+ switch (type) {
+ case SVP_LOG_VL2:
+ rlen = sizeof (svp_log_vl2_t);
+ break;
+ case SVP_LOG_VL3:
+ rlen = sizeof (svp_log_vl3_t);
+ break;
+ default:
+ /*
+ * If we don't know the type of log record we have,
+ * we cannot determine the size of the record, so we
+ * cannot continue past this.
+ */
+ show_printf("Log %-4zu: Log type = %s", ++total,
+ typestr);
+ return;
+ }
+
+ if (len < rlen) {
+ show_printf("Log %-4zu %s runt", ++total, typestr);
+ return;
+ }
+
+ /* These are the same in SVP_LOG_VL2 and SVP_LOG_VL3 records */
+ show_printf("Log %-4zu Log type = %s", ++total, typestr);
+
+ uuid_parse(uuid, u.vl2->svl2_id);
+ show_printf("%8s UUID = %s", "", uuid);
+
+ switch (type) {
+ case SVP_LOG_VL2:
+ show_printf("%8s MAC = %s", "",
+ ether_ntoa((struct ether_addr *)u.vl2->svl2_mac));
+ show_printf("%8s Vnet = %u", "",
+ ntohl(u.vl2->svl2_vnetid));
+ u.vl2++;
+ break;
+ case SVP_LOG_VL3:
+ svp_addr_str(u.vl3->svl3_ip, NULL, addr, sizeof (addr));
+
+ show_printf("%8s VLAN = %hu", "",
+ ntohs(u.vl3->svl3_vlan));
+ show_printf("%8s Address = %s", "", addr);
+ show_printf("%8s Vnet = %u", "",
+ ntohl(u.vl3->svl3_vnetid));
+ u.vl3++;
+ break;
+ }
+
+ len -= rlen;
+ show_space();
+ }
+ show_printf("Total log records = %zu", total);
+}
+
+static void
+do_svp_lrm_req(void *data, int len)
+{
+ /*
+ * Sized large enough to hold the expected size message
+ * (formatted below) if there's a length mismatch.
+ */
+ char mismatch_str[64] = { 0 };
+ svp_lrm_req_t *req = data;
+ size_t expected_sz = sizeof (*req);
+ size_t i, n;
+
+ n = ntohl(req->svrr_count);
+
+ /* IDs are 16-byte UUIDs */
+ expected_sz += n * UUID_LEN;
+ if (len != expected_sz) {
+ (void) snprintf(mismatch_str, sizeof (mismatch_str),
+ " (expected %zu bytes, actual size is %d bytes)",
+ expected_sz, len);
+ }
+ show_printf("ID Count = %u%s", n, mismatch_str);
+ if (len != expected_sz)
+ return;
+
+ for (i = 0; i < n; i++) {
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ uuid_parse(uuid, &req->svrr_ids[UUID_LEN * i]);
+ show_printf("%-4s %s", (i == 0) ? "IDs:" : "", uuid);
+ }
+}
+
+static void
+do_svp_lrm_ack(void *data, int len)
+{
+ svp_lrm_ack_t *ack = data;
+ char status[STATUSSTR_LEN];
+
+ svp_status_str(ntohl(ack->svra_status), status, sizeof (status));
+ show_printf("Status = %s", status);
+}
+
+static void
+do_svp_shootdown(void *data, int len)
+{
+ svp_shootdown_t *sd = data;
+
+ show_printf("Vnet = %u", ntohl(sd->svsd_vnetid));
+ show_printf("MAC Address = %s",
+ ether_ntoa((struct ether_addr *)sd->svsd_mac));
+}
+
+static struct svp_len_tbl {
+ uint16_t slt_op;
+ size_t slt_len;
+} svp_len_tbl[] = {
+ { SVP_R_UNKNOWN, 0 },
+ { SVP_R_PING, 0 },
+ { SVP_R_PONG, 0 },
+ { SVP_R_VL2_REQ, sizeof (svp_vl2_req_t) },
+ { SVP_R_VL2_ACK, sizeof (svp_vl2_ack_t) },
+ { SVP_R_VL3_REQ, sizeof (svp_vl3_req_t) },
+ { SVP_R_VL3_ACK, sizeof (svp_vl3_ack_t) },
+ { SVP_R_BULK_REQ, sizeof (svp_bulk_req_t) },
+ { SVP_R_BULK_ACK, sizeof (svp_bulk_ack_t) },
+ { SVP_R_LOG_REQ, sizeof (svp_log_req_t) },
+ { SVP_R_LOG_ACK, 0 },
+ { SVP_R_LOG_RM, sizeof (svp_lrm_req_t) },
+ { SVP_R_LOG_RM_ACK, sizeof (svp_lrm_ack_t) },
+ { SVP_R_SHOOTDOWN, sizeof (svp_shootdown_t) },
+};
+
+static boolean_t
+svp_check_runt(uint16_t op, int len)
+{
+ if (op > SVP_R_SHOOTDOWN)
+ return (B_FALSE);
+
+ if (len < svp_len_tbl[op].slt_len) {
+ char opstr[OPSTR_LEN];
+
+ svp_op_str(op, opstr, sizeof (opstr));
+ show_printf("%s Runt", opstr);
+ show_space();
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+int
+interpret_svp(int flags, char *data, int fraglen)
+{
+ svp_req_t *req = (svp_req_t *)data;
+ char opstr[OPSTR_LEN];
+ uint16_t op;
+ boolean_t crc_ok;
+
+ if (fraglen < sizeof (svp_req_t)) {
+ if (flags & F_SUM)
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "SVP RUNT");
+ if (flags & F_DTAIL)
+ show_header("SVP RUNT: ", "Short packet", fraglen);
+
+ return (fraglen);
+ }
+
+ op = ntohs(req->svp_op);
+ svp_op_str(op, opstr, sizeof (opstr));
+
+ crc_ok = svp_check_crc(data, fraglen);
+
+ if (flags & F_SUM) {
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "SVP V=%hu OP=%s ID=%u%s", ntohs(req->svp_ver), opstr,
+ ntohl(req->svp_id), crc_ok ? "" : " (BAD CRC)");
+ }
+
+ if (flags & F_DTAIL) {
+ show_header("SVP: ", "SVP Header", sizeof (svp_req_t));
+ show_space();
+ show_printf("Version = %hu", ntohs(req->svp_ver));
+ show_printf("Op = %s", opstr);
+ show_printf("Packet length = %u bytes%s", ntohl(req->svp_size),
+ (ntohl(req->svp_size) == fraglen - sizeof (*req)) ?
+ "" : " (mismatch)");
+ show_printf("Id = %u", ntohl(req->svp_id));
+ show_printf("CRC = %x%s", ntohl(req->svp_crc32),
+ crc_ok ? "" : " (bad)");
+ show_space();
+
+ req++;
+ fraglen -= sizeof (*req);
+
+ /*
+ * Since we cannot know the length of an unknown op,
+ * svp_check_runt() returns B_TRUE for both truncated packets
+ * and unknown packets -- we have nothing meaningful besides
+ * the header we could print anyway.
+ */
+ if (svp_check_runt(op, fraglen))
+ return (fraglen);
+
+ switch (op) {
+ case SVP_R_VL2_REQ:
+ do_svp_vl2_req(req, fraglen);
+ break;
+ case SVP_R_VL2_ACK:
+ do_svp_vl2_ack(req, fraglen);
+ break;
+ case SVP_R_VL3_REQ:
+ do_svp_vl3_req(req, fraglen);
+ break;
+ case SVP_R_VL3_ACK:
+ do_svp_vl3_ack(req, fraglen);
+ break;
+ case SVP_R_BULK_REQ:
+ do_svp_bulk_req(req, fraglen);
+ break;
+ case SVP_R_BULK_ACK:
+ do_svp_bulk_ack(req, fraglen);
+ break;
+ case SVP_R_LOG_REQ:
+ do_svp_log_req(req, fraglen);
+ break;
+ case SVP_R_LOG_ACK:
+ do_svp_log_ack(req, fraglen);
+ break;
+ case SVP_R_LOG_RM:
+ do_svp_lrm_req(req, fraglen);
+ break;
+ case SVP_R_LOG_RM_ACK:
+ do_svp_lrm_ack(req, fraglen);
+ break;
+ case SVP_R_SHOOTDOWN:
+ do_svp_shootdown(req, fraglen);
+ break;
+ }
+
+ show_space();
+ }
+
+ return (0);
+}