diff options
author | Jason King <jason.king@joyent.com> | 2018-06-13 18:22:09 -0500 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2019-01-17 01:52:03 +0000 |
commit | a947aa5f9e3d25d6638e832f6ef7015d604e3a2e (patch) | |
tree | 60c5bd56cdd59cdbb69e943f6a119ec61f9990c7 /usr/src | |
parent | 30705f8dce180a0882752e20319b9186ebd10aa3 (diff) | |
download | illumos-joyent-a947aa5f9e3d25d6638e832f6ef7015d604e3a2e.tar.gz |
OS-7503 snoop(1m) should learn about SVP
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile | 6 | ||||
-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_rport.c | 9 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c | 556 | ||||
-rw-r--r-- | usr/src/lib/varpd/svp/Makefile | 7 |
5 files changed, 574 insertions, 7 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile index 9e6654e8f7..88a13c99e1 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile @@ -40,8 +40,8 @@ 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 @@ -51,7 +51,7 @@ 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:%=-M%) CERRWARN += -_gcc=-Wno-switch CERRWARN += -_gcc=-Wno-implicit-function-declaration 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 991abae186..fc63d3987f 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h @@ -24,7 +24,7 @@ * Use is subject to license terms. * * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright 2015 Joyent, Inc. + * Copyright 2018 Joyent, Inc. */ #ifndef _SNOOP_H @@ -275,6 +275,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_rport.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c index 76ab7f2da0..8e474fe470 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..54f4dded8c --- /dev/null +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c @@ -0,0 +1,556 @@ +/* + * 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. All rights reserved. + */ + +/* + * Decode SVP (SmartDC VxLAN Protocol) packets + */ + +#include <inttypes.h> +#include <sys/crc32.h> +#include <uuid/uuid.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); +} diff --git a/usr/src/lib/varpd/svp/Makefile b/usr/src/lib/varpd/svp/Makefile index 275f07bf8b..b4dbf8f017 100644 --- a/usr/src/lib/varpd/svp/Makefile +++ b/usr/src/lib/varpd/svp/Makefile @@ -10,11 +10,13 @@ # # -# Copyright 2015 Joyent, Inc. +# Copyright 2018 Joyent, Inc. # include ../../Makefile.lib +HDRS = libvarpd_svp_prot.h # For snoop +HDRDIR = common SUBDIRS = $(MACH) $(BUILD64)SUBDIRS += $(MACH64) @@ -28,7 +30,8 @@ lint := TARGET = lint all clean clobber install lint: $(SUBDIRS) -install_h: +install: install_h +install_h: $(ROOTHDRS) check: |