Index: sbin/ping/ping.c =================================================================== RCS file: /cvs/src/sbin/ping/ping.c,v retrieving revision 1.240 diff -u -p -r1.240 ping.c --- sbin/ping/ping.c 11 Feb 2020 18:41:39 -0000 1.240 +++ sbin/ping/ping.c 14 Dec 2020 04:31:05 -0000 @@ -153,6 +153,7 @@ int options; #define F_TOS 0x1000 #define F_AUD_RECV 0x2000 #define F_AUD_MISS 0x4000 +#define F_SO_TSTAMP 0x8000 /* multicast options */ int moptions; @@ -217,6 +218,8 @@ const char *pr_addr(struct sockaddr *, void pr_pack(u_char *, int, struct msghdr *); __dead void usage(void); +int get_tstamp(struct msghdr *, struct timespec *); + /* IPv4 specific functions */ void pr_ipopt(int, u_char *); int in_cksum(u_short *, int); @@ -297,8 +300,8 @@ main(int argc, char *argv[]) preload = 0; datap = &outpack[ECHOLEN + ECHOTMLEN]; while ((ch = getopt(argc, argv, v6flag ? - "c:DdEefHh:I:i:Ll:mNnp:qS:s:T:V:vw:" : - "DEI:LRS:c:defHi:l:np:qs:T:t:V:vw:")) != -1) { + "c:DdEefHh:I:i:Ll:mNnp:qS:s:T:V:vw:x" : + "DEI:LRS:c:defHi:l:np:qs:T:t:V:vw:x")) != -1) { switch(ch) { case 'c': npackets = strtonum(optarg, 0, INT64_MAX, &errstr); @@ -429,6 +432,9 @@ main(int argc, char *argv[]) errx(1, "maxwait value is %s: %s", errstr, optarg); break; + case 'x': + options |= F_SO_TSTAMP; + break; default: usage(); } @@ -567,6 +573,13 @@ main(int argc, char *argv[]) (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &optval, sizeof(optval)); + if (options & F_SO_TSTAMP) { + optval = 1; + if (setsockopt(s, SOL_SOCKET, SO_MONOSTAMP, + &optval, sizeof(optval)) == -1) + warn("setsockopt SO_MONOSTAMP"); + } + if ((options & F_FLOOD) && (options & F_INTERVAL)) errx(1, "-f and -i options are incompatible"); @@ -1145,11 +1158,12 @@ pr_pack(u_char *buf, int cc, struct msgh struct ip *ip = NULL; struct icmp *icp = NULL; struct icmp6_hdr *icp6 = NULL; - struct timespec ts, tp; + struct timespec ts, tp, diff; struct payload payload; struct sockaddr *from; socklen_t fromlen; double triptime = 0; + int64_t xtriptime = 0; int i, dupflag; int hlen = -1, hoplim = -1, echo_reply = 0; u_int16_t seq; @@ -1253,15 +1267,25 @@ pr_pack(u_char *buf, int cc, struct msgh tp.tv_nsec = betoh64(tv64->tv64_nsec) - tv64_offset.tv64_nsec; - timespecsub(&ts, &tp, &ts); - triptime = ((double)ts.tv_sec) * 1000.0 + - ((double)ts.tv_nsec) / 1000000.0; + timespecsub(&ts, &tp, &diff); + triptime = ((double)diff.tv_sec) * 1000.0 + + ((double)diff.tv_nsec) / 1000000.0; tsum += triptime; tsumsq += triptime * triptime; if (triptime < tmin) tmin = triptime; if (triptime > tmax) tmax = triptime; + + if (options & F_SO_TSTAMP && + get_tstamp(mhdr, &ts) != -1) { + uint64_t tsnsec = ts.tv_sec * 1000000000 + + ts.tv_nsec; + uint64_t tpnsec = tp.tv_sec * 1000000000 + + tp.tv_nsec; + + xtriptime = tsnsec - tpnsec; + } } if (TST(ntohs(seq) % mx_dup_ck)) { @@ -1287,6 +1311,10 @@ pr_pack(u_char *buf, int cc, struct msgh printf(" ttl=%d", ip->ip_ttl); if (cc >= ECHOLEN + ECHOTMLEN) printf(" time=%.3f ms", triptime); + if (options & F_SO_TSTAMP) { + printf(" xtime=%.3f ms", + (double)xtriptime / 1000000.0); + } if (dupflag) printf(" (DUP!)"); /* check the data */ @@ -1889,6 +1917,27 @@ get_hoplim(struct msghdr *mhdr) cm->cmsg_type == IPV6_HOPLIMIT && cm->cmsg_len == CMSG_LEN(sizeof(int))) return(*(int *)CMSG_DATA(cm)); + } + + return(-1); +} + +int +get_tstamp(struct msghdr *mhdr, struct timespec *ts) +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(-1); + + if (cm->cmsg_level == SOL_SOCKET && + cm->cmsg_type == SCM_MONOSTAMP && + cm->cmsg_len == CMSG_LEN(sizeof(*ts))) { + *ts = *(struct timespec *)CMSG_DATA(cm); + return (0); + } } return(-1); Index: sys/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/conf/GENERIC,v retrieving revision 1.273 diff -u -p -r1.273 GENERIC --- sys/conf/GENERIC 30 Sep 2020 14:51:17 -0000 1.273 +++ sys/conf/GENERIC 14 Dec 2020 04:31:07 -0000 @@ -82,6 +82,7 @@ pseudo-device msts 1 # MSTS line discipl pseudo-device endrun 1 # EndRun line discipline pseudo-device vnd 4 # vnode disk devices pseudo-device ksyms 1 # kernel symbols device +pseudo-device kstat # kernel statistics #pseudo-device dt # Dynamic Tracer # clonable devices Index: sys/dev/pci/if_mcx.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_mcx.c,v retrieving revision 1.75 diff -u -p -r1.75 if_mcx.c --- sys/dev/pci/if_mcx.c 6 Nov 2020 02:50:02 -0000 1.75 +++ sys/dev/pci/if_mcx.c 14 Dec 2020 04:31:07 -0000 @@ -2394,6 +2394,7 @@ struct mcx_softc { struct kstat *sc_kstat_rfc3635; unsigned int sc_kstat_mtmp_count; struct kstat **sc_kstat_mtmp; + struct kstat *sc_kstat_calibrate; #endif }; #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) @@ -6514,11 +6515,14 @@ static void mcx_calibrate_first(struct mcx_softc *sc) { struct mcx_calibration *c = &sc->sc_calibration[0]; + int s; sc->sc_calibration_gen = 0; + s = splhigh(); c->c_ubase = mcx_uptime(); c->c_tbase = mcx_timer(sc); + splx(s); c->c_tdiff = 0; timeout_add_sec(&sc->sc_calibrate, MCX_CALIBRATE_FIRST); @@ -6532,6 +6536,7 @@ mcx_calibrate(void *arg) struct mcx_softc *sc = arg; struct mcx_calibration *nc, *pc; unsigned int gen; + int s; if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING)) return; @@ -6546,8 +6551,10 @@ mcx_calibrate(void *arg) nc->c_uptime = pc->c_ubase; nc->c_timestamp = pc->c_tbase; + s = splhigh(); /* XXX critical section */ nc->c_ubase = mcx_uptime(); nc->c_tbase = mcx_timer(sc); + splx(s); nc->c_udiff = (nc->c_ubase - nc->c_uptime) >> MCX_TIMESTAMP_SHIFT; nc->c_tdiff = (nc->c_tbase - nc->c_timestamp) >> MCX_TIMESTAMP_SHIFT; @@ -8087,6 +8094,99 @@ mcx_kstat_attach_ppcnt(struct mcx_softc return (ks); } +struct mcx_kstat_calibrate { + struct kstat_kv kc_timestamp; + struct kstat_kv kc_uptime; + struct kstat_kv kc_tbase; + struct kstat_kv kc_ubase; + struct kstat_kv kc_tdiff; + struct kstat_kv kc_udiff; + + struct kstat_kv kc_timer; + struct kstat_kv kc_know; + struct kstat_kv kc_tnow; + struct kstat_kv kc_diff; +}; + +static int +mcx_kstat_calibrate_read(struct kstat *ks) +{ + struct mcx_softc *sc = ks->ks_softc; + struct mcx_kstat_calibrate *kc = ks->ks_data; + const struct mcx_calibration *c; + unsigned int gen; + uint64_t t, u; + int s; + + gen = sc->sc_calibration_gen; + membar_consumer(); + c = &sc->sc_calibration[gen % nitems(sc->sc_calibration)]; + + if (c->c_tdiff == 0) + return (ENETDOWN); + + s = splhigh(); /* crit_enter */ + nanouptime(&ks->ks_updated); + t = mcx_timer(sc); + splx(s); + + kstat_kv_u64(&kc->kc_timestamp) = c->c_timestamp; + kstat_kv_u64(&kc->kc_uptime) = c->c_uptime; + kstat_kv_u64(&kc->kc_tbase) = c->c_tbase; + kstat_kv_u64(&kc->kc_ubase) = c->c_ubase; + kstat_kv_u64(&kc->kc_tdiff) = c->c_tdiff; + kstat_kv_u64(&kc->kc_udiff) = c->c_udiff; + + kstat_kv_u64(&kc->kc_timer) = t; + + t -= c->c_timestamp; + t *= c->c_udiff; + t /= c->c_tdiff; + t += c->c_uptime; + + NSEC_TO_TIMESPEC(t, &kstat_kv_timespec(&kc->kc_tnow)); + kstat_kv_timespec(&kc->kc_know) = ks->ks_updated; + + u = TIMESPEC_TO_NSEC(&ks->ks_updated); + kstat_kv_s64(&kc->kc_diff) = u - t; + + return (0); +} + +static struct kstat * +mcx_kstat_attach_calibrate(struct mcx_softc *sc) +{ + struct kstat *ks; + struct mcx_kstat_calibrate *kc; + + ks = kstat_create(DEVNAME(sc), 0, "timestamp", 0, KSTAT_T_KV, 0); + if (ks == NULL) + return (NULL); + + kc = malloc(sizeof(*kc), M_DEVBUF, M_WAITOK); + + kstat_kv_init(&kc->kc_timestamp, "c_timestamp", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_uptime, "c_uptime", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_tbase, "c_tbase", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_ubase, "c_ubase", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_tdiff, "c_tdiff", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_udiff, "c_udiff", KSTAT_KV_T_UINT64); + + kstat_kv_init(&kc->kc_timer, "timer", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_know, "know", KSTAT_KV_T_MONOTIME); + kstat_kv_init(&kc->kc_tnow, "tnow", KSTAT_KV_T_MONOTIME); + kstat_kv_init(&kc->kc_diff, "know-tnow", KSTAT_KV_T_INT64); + + ks->ks_softc = sc; + ks->ks_data = kc; + ks->ks_datalen = sizeof(*kc); + ks->ks_read = mcx_kstat_calibrate_read; + + kstat_install(ks); + + return (ks); +} + static void mcx_kstat_attach(struct mcx_softc *sc) { @@ -8101,6 +8201,8 @@ mcx_kstat_attach(struct mcx_softc *sc) mcx_kstat_attach_tmps(sc); mcx_kstat_attach_queues(sc); + + sc->sc_kstat_calibrate = mcx_kstat_attach_calibrate(sc); } static int Index: sys/kern/kern_pledge.c =================================================================== RCS file: /cvs/src/sys/kern/kern_pledge.c,v retrieving revision 1.267 diff -u -p -r1.267 kern_pledge.c --- sys/kern/kern_pledge.c 29 Oct 2020 21:15:27 -0000 1.267 +++ sys/kern/kern_pledge.c 14 Dec 2020 04:31:07 -0000 @@ -1367,6 +1367,7 @@ pledge_sockopt(struct proc *p, int set, case SOL_SOCKET: switch (optname) { case SO_TIMESTAMP: + case SO_MONOSTAMP: return 0; } break; Index: sys/kern/uipc_mbuf.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_mbuf.c,v retrieving revision 1.275 diff -u -p -r1.275 uipc_mbuf.c --- sys/kern/uipc_mbuf.c 21 Jun 2020 05:37:26 -0000 1.275 +++ sys/kern/uipc_mbuf.c 14 Dec 2020 04:31:07 -0000 @@ -1468,6 +1468,15 @@ m_microtime(const struct mbuf *m, struct timeradd(&btv, &utv, tv); } else microtime(tv); +} + +void +m_nanouptime(const struct mbuf *m, struct timespec *ts) +{ + if (ISSET(m->m_pkthdr.csum_flags, M_TIMESTAMP)) + NSEC_TO_TIMESPEC(m->m_pkthdr.ph_timestamp, ts); + else + nanouptime(ts); } void * Index: sys/kern/uipc_socket.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.250 diff -u -p -r1.250 uipc_socket.c --- sys/kern/uipc_socket.c 17 Nov 2020 14:45:42 -0000 1.250 +++ sys/kern/uipc_socket.c 14 Dec 2020 04:31:07 -0000 @@ -1728,6 +1728,7 @@ sosetopt(struct socket *so, int level, i case SO_OOBINLINE: case SO_TIMESTAMP: case SO_ZEROIZE: + case SO_MONOSTAMP: if (m == NULL || m->m_len < sizeof (int)) return (EINVAL); if (*mtod(m, int *)) @@ -1901,6 +1902,7 @@ sogetopt(struct socket *so, int level, i case SO_OOBINLINE: case SO_TIMESTAMP: case SO_ZEROIZE: + case SO_MONOSTAMP: *mtod(m, int *) = so->so_options & optname; break; Index: sys/netinet/ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.352 diff -u -p -r1.352 ip_input.c --- sys/netinet/ip_input.c 16 Nov 2020 06:44:38 -0000 1.352 +++ sys/netinet/ip_input.c 14 Dec 2020 04:31:07 -0000 @@ -1704,6 +1704,15 @@ ip_savecontrol(struct inpcb *inp, struct if (*mp) mp = &(*mp)->m_next; } + if (inp->inp_socket->so_options & SO_MONOSTAMP) { + struct timespec ts; + + m_nanouptime(m, &ts); + *mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts), + SCM_MONOSTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } if (inp->inp_flags & INP_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, Index: sys/netinet/raw_ip.c =================================================================== RCS file: /cvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.119 diff -u -p -r1.119 raw_ip.c --- sys/netinet/raw_ip.c 4 Feb 2019 21:40:52 -0000 1.119 +++ sys/netinet/raw_ip.c 14 Dec 2020 04:31:07 -0000 @@ -175,7 +175,8 @@ rip_input(struct mbuf **mp, int *offp, i if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) { if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + ISSET(last->inp_socket->so_options, + SO_TIMESTAMP|SO_MONOSTAMP)) ip_savecontrol(last, &opts, ip, n); if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv, @@ -192,7 +193,8 @@ rip_input(struct mbuf **mp, int *offp, i } if (last) { if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + ISSET(last->inp_socket->so_options, + SO_TIMESTAMP|SO_MONOSTAMP)) ip_savecontrol(last, &opts, ip, m); if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv, sintosa(&ripsrc), m, opts) == 0) { Index: sys/netinet/udp_usrreq.c =================================================================== RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.262 diff -u -p -r1.262 udp_usrreq.c --- sys/netinet/udp_usrreq.c 22 Aug 2020 17:54:57 -0000 1.262 +++ sys/netinet/udp_usrreq.c 14 Dec 2020 04:31:07 -0000 @@ -604,11 +604,11 @@ udp_sbappend(struct inpcb *inp, struct m #ifdef INET6 if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS || - so->so_options & SO_TIMESTAMP)) + ISSET(so->so_options, SO_TIMESTAMP|SO_MONOSTAMP))) ip6_savecontrol(inp, m, &opts); #endif /* INET6 */ if (ip && (inp->inp_flags & INP_CONTROLOPTS || - so->so_options & SO_TIMESTAMP)) + ISSET(so->so_options, SO_TIMESTAMP|SO_MONOSTAMP))) ip_savecontrol(inp, &opts, ip, m); #ifdef INET6 if (ip6 && (inp->inp_flags & IN6P_RECVDSTPORT)) { Index: sys/netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.230 diff -u -p -r1.230 ip6_input.c --- sys/netinet6/ip6_input.c 16 Nov 2020 06:44:39 -0000 1.230 +++ sys/netinet6/ip6_input.c 14 Dec 2020 04:31:07 -0000 @@ -931,6 +931,15 @@ ip6_savecontrol(struct inpcb *in6p, stru if (*mp) mp = &(*mp)->m_next; } + if (in6p->inp_socket->so_options & SO_MONOSTAMP) { + struct timespec ts; + + m_nanouptime(m, &ts); + *mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts), + SCM_MONOSTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } /* RFC 2292 sec. 5 */ if ((in6p->inp_flags & IN6P_PKTINFO) != 0) { Index: sys/sys/kstat.h =================================================================== RCS file: /cvs/src/sys/sys/kstat.h,v retrieving revision 1.1 diff -u -p -r1.1 kstat.h --- sys/sys/kstat.h 6 Jul 2020 03:56:51 -0000 1.1 +++ sys/sys/kstat.h 14 Dec 2020 04:31:07 -0000 @@ -79,6 +79,10 @@ enum kstat_kv_type { KSTAT_KV_T_STR, /* trailing string */ KSTAT_KV_T_BYTES, /* trailing bytes */ KSTAT_KV_T_TEMP, /* temperature (uK) */ + + KSTAT_KV_T_REALTIME, /* struct timespec */ + KSTAT_KV_T_MONOTIME, /* struct timespec */ + KSTAT_KV_T_INTERVAL, /* struct timespec */ }; /* units only apply to integer types */ @@ -99,6 +103,7 @@ struct kstat_kv { uint32_t v_u32; int32_t v_s32; size_t v_len; + struct timespec v_timespec; } kv_v; enum kstat_kv_type kv_type; enum kstat_kv_unit kv_unit; @@ -112,6 +117,7 @@ struct kstat_kv { #define kstat_kv_s32(_kv) (_kv)->kv_v.v_s32 #define kstat_kv_len(_kv) (_kv)->kv_v.v_len #define kstat_kv_temp(_kv) (_kv)->kv_v.v_u64 +#define kstat_kv_timespec(_kv) (_kv)->kv_v.v_timespec #ifdef _KERNEL Index: sys/sys/mbuf.h =================================================================== RCS file: /cvs/src/sys/sys/mbuf.h,v retrieving revision 1.250 diff -u -p -r1.250 mbuf.h --- sys/sys/mbuf.h 8 Aug 2020 19:53:02 -0000 1.250 +++ sys/sys/mbuf.h 14 Dec 2020 04:31:07 -0000 @@ -444,6 +444,7 @@ struct mbuf *m_dup_pkt(struct mbuf *, un int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); void m_microtime(const struct mbuf *, struct timeval *); +void m_nanouptime(const struct mbuf *, struct timespec *); static inline struct mbuf * m_freemp(struct mbuf **mp) Index: sys/sys/socket.h =================================================================== RCS file: /cvs/src/sys/sys/socket.h,v retrieving revision 1.99 diff -u -p -r1.99 socket.h --- sys/sys/socket.h 29 Oct 2020 21:15:27 -0000 1.99 +++ sys/sys/socket.h 14 Dec 2020 04:31:07 -0000 @@ -97,6 +97,7 @@ typedef __sa_family_t sa_family_t; /* so #define SO_TIMESTAMP 0x0800 /* timestamp received dgram traffic */ #define SO_BINDANY 0x1000 /* allow bind to any address */ #define SO_ZEROIZE 0x2000 /* zero out all mbufs sent over socket */ +#define SO_MONOSTAMP 0x4000 /* monotime stamp rxed dgram traffic */ /* * Additional options, not kept in so_options. @@ -523,6 +524,7 @@ struct cmsghdr { /* "Socket"-level control message types: */ #define SCM_RIGHTS 0x01 /* access rights (array of int) */ #define SCM_TIMESTAMP 0x04 /* timestamp (struct timeval) */ +#define SCM_MONOSTAMP 0x08 /* timestamp (struct timespec) */ #ifndef _KERNEL Index: usr.bin/kstat/kstat.c =================================================================== RCS file: /cvs/src/usr.bin/kstat/kstat.c,v retrieving revision 1.6 diff -u -p -r1.6 kstat.c --- usr.bin/kstat/kstat.c 13 Aug 2020 12:37:16 -0000 1.6 +++ usr.bin/kstat/kstat.c 14 Dec 2020 04:31:08 -0000 @@ -351,6 +351,7 @@ kstat_kv(const void *d, ssize_t len) buf = d; do { kv = (const struct kstat_kv *)buf; + const struct timespec *ts; buf += sizeof(*kv); len -= sizeof(*kv); @@ -401,6 +402,19 @@ kstat_kv(const void *d, ssize_t len) printf("%.2f degC", (f - 273150000.0) / 1000000.0); break; + case KSTAT_KV_T_MONOTIME: + ts = &kstat_kv_timespec(kv); + printf("monotime %lld.%09ld", ts->tv_sec, ts->tv_nsec); + break; + case KSTAT_KV_T_REALTIME: + ts = &kstat_kv_timespec(kv); + printf("realtime %lld.%09ld", ts->tv_sec, ts->tv_nsec); + break; + case KSTAT_KV_T_INTERVAL: + ts = &kstat_kv_timespec(kv); + printf("interval %lld.%09ld", ts->tv_sec, ts->tv_nsec); + break; + default: printf("unknown type %u, stopping\n", kv->kv_type); return; @@ -474,17 +488,17 @@ kstat_list(struct kstat_tree *kt, int fd } else id = ksreq->ks_id; - if (!kstat_filter_entry(kfs, ksreq)) { + if (kse->serrno != 0 || !kstat_filter_entry(kfs, ksreq)) { free(ksreq->ks_data); free(kse); continue; } - if (RBT_INSERT(kstat_tree, kt, kse) != NULL) - errx(1, "duplicate kstat entry"); - - if (kse->serrno != 0) - continue; + if (RBT_INSERT(kstat_tree, kt, kse) != NULL) { + errx(1, "duplicate kstat entry %s:%u:%s:%u", + ksreq->ks_provider, ksreq->ks_instance, + ksreq->ks_name, ksreq->ks_unit); + } while (ksreq->ks_datalen > len) { len = ksreq->ks_datalen;