diff options
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.sbin')
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/Makefile | 1 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/arp.c | 7 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ndp.c | 9 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/route.c | 90 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c | 30 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile | 7 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c | 12 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h | 3 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c | 13 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c | 9 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c | 557 |
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); +} |