Network Working Group Jeffrey Mogul, DECWRL, Internet-Draft David Mills, UDel Expires: 15 July 1998 Jan Brittenson, Sun 12 January 1998 Pulse-Per-Second API for UNIX draft-mogul-pps-api-01.txt STATUS OF THIS MEMO This document is an Internet-Draft. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." To learn the current status of any Internet-Draft, please check the "1id-abstracts.txt" listing contained in the Internet-Drafts Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or ftp.isi.edu (US West Coast). Distribution of this document is unlimited. Please send comments to the authors. ABSTRACT RFC1589 describes a UNIX kernel implementation model for high-precision time-keeping. This is meant for use in conjunction with the Network Time Protocol (NTP, RFC1305), or similar time synchronization protocols. One aspect of this model is an accurate interface to the high-accuracy, one pulse-per-second (PPS) output typically available from precise time sources (such as a GPS or GOES receiver). RFC1589 did not define an API for managing the PPS facility. This document specifies such an API. TABLE OF CONTENTS 1 Introduction 2 2 Data types for representing timestamps 3 Mogul, Mills, Brittenson [Page 1] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 2.1 Resolution 4 2.2 Time scale 4 3 API 4 3.1 New data structures 5 3.2 Mode bit definitions 6 3.3 New functions 7 3.3.1 New functions: access to PPS events 7 3.3.2 New functions: setting PPS mode bits 8 3.3.3 New functions: access to PPS timestamps 9 3.3.4 New functions: disciplining the kernel timebase 10 3.4 Example 10 4 PPSDISC Line discipline 11 4.1 Example 11 5 Security Considerations 12 6 Acknowledgements 12 7 References 13 8 Authors' addresses 13 1 Introduction RFC1589 [3] describes a model and programming interface for generic operating system software that manages the system clock and timer functions. The model provides improved accuracy and stability for most workstations and servers using the Network Time Protocol (NTP) [2] or similar time synchronization protocol. The model supports the use of external timing sources, such as the precision pulse-per-second (PPS) signals typically available from precise time sources (such as a GPS or GOES receiver). However, RFC1589 did not define an application programming interface (API) for the PPS facility. This document specifies such an interface, for use with UNIX (or UNIX-like) operating systems. Such systems often conform to the ``Single UNIX Specification'' [4], sometimes known as POSIX. One convenient means to provide a PPS signal to a computer system is to connect that signal to a modem-control pin on a serial-line interface to the computer. The Data Carrier Detect (DCD) pin is frequently used for this purpose. Typically, the time-code output of the time source is transmitted to the computer over the same serial line. The computer detects a signal transition on the DCD pin, usually by receiving an interrupt. Although existing practice has focussed on the use of serial lines and DCD transitions, PPS signals might also be delivered by other kinds of devices. The API specified in this document does not require the use of a serial line, although it may be somewhat biased in that direction. Mogul, Mills, Brittenson [Page 2] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 The typical use of this facility is for the operating system to record a high-resolution timestamp as soon as possible after it detects a PPS signal transition (usually indicated by an interrupt). This timestamp can then be made available, with less stringent delay constraints, to timekeeping software. The software can compare the captured timestamp to the received time-code to accurately determine the absolute offset between the system clock and the precise time source. The operating system may also deliver the PPS event immediately to a procedure used to discipline its internal timebase, such as the hardpps() procedure described in RFC1589. The API specified in this document allows for one or more signal sources attached to a computer system to provide PPS inputs, at the option of user-level software. User-level software may obtain DCD-transition timestamps for any of these PPS sources. User-level software may optionally specify that at most one of these PPS sources be used to discipline the system's internal timebase. Although the primary purpose of this API is for capturing true pulse-per-second events, the API may also be used for accurately timestamping events of other periods, or even aperiodic events, when these can be expressed as signal transitions. This document does not define how the API must be implemented, and does not specify constraints on the accuracy, resolution, or latency of the PPS feature. However, the utility of this feature is inversely proportional to the delay (and variance of delay), and implementors are encouraged to take this seriously. In principle, the rate of events to be captured, or the frequency of the signals, can range from once per day (or less often) to several thousand per second. However, since in most implementations the timestamping function will be implemented as a processor interrupt at a relatively high priority, it is prudent to limit the rate of such events. This may be done either by mechanisms in the hardware that generates the signals, or by the operating system. 2 Data types for representing timestamps Computer systems use various representations of time. Because this API is concerned with the provision of high-accuracy, high-resolution time information, the choice of representation is significant. (Here we consider only binary representations, not human-format representations.) The two interesting questions are: Mogul, Mills, Brittenson [Page 3] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 1. what is the resolution of the representation? 2. what time scale is represented? These questions often lead to contentious arguments. Since this API is intended for use with NTP and POSIX-compliant systems, however, we can limit the choices to representations compatible with existing NTP and POSIX practice, even if that practice is considered ``wrong'' in some quarters. 2.1 Resolution In the NTP protocol, ``timestamps are represented as a 64-bit unsigned fixed-point number, in seconds relative to 0h on 1 January 1900. The integer part is in the first 32 bits and the fraction part in the last 32 bits [...] The precision of this representation is about 200 picoseconds'' [2]. However, most computer systems cannot measure time to this resolution (this represents a clock rate of 5 GHz). The POSIX gettimeofday() function returns a ``struct timeval'' value, with a resolution of 1 microsecond. The POSIX clock_settime() function returns a ``struct timespec'' value, with a resolution of 1 nanosecond. This API uses the ``struct timespec'' representation, since in a general-purpose computer system it is just barely feasible to measure time to a precision of a few microseconds. It might become possible to improve this resolution within the next few years. We do not expect it to be feasible for a general-purpose system to measure time to a precision of less than one nanosecond in the foreseeable future. 2.2 Time scale Several different time scales have been proposed for use in computer systems. UTC and TAI are the two obvious candidates. Some people would prefer the use of TAI, which is identical to UTC except that it does not correct for leap seconds. Their preference for TAI stems from the difficulty of computing precise time differences when leap seconds are involved, especially when using times in the future (for which the exact number of leap seconds is, in general, unknowable). However, POSIX and NTP both use UTC, albeit with different base dates. Given that support for TAI would, in general, require other changes to the POSIX specification, This API uses the POSIX base date of midnight January 1, 1970. 3 API A PPS facility can be used in two different ways: Mogul, Mills, Brittenson [Page 4] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 1. An application can obtain a timestamp, using the system's internal timebase, for the most recent PPS event. 2. A kernel may directly utilize PPS events to discipline its internal timebase, thereby providing highly accurate time to all applications. This API supports both uses, individually or in combination. The timestamping feature may be used on any number of PPS sources simultaneously; the timebase-disciplining feature may be used with at most one PPS source. Although the proper implementation of this API requires support from the kernel of a UNIX system, this document defines the API in terms of a set of library routines. This gives the implementor some freedom to divide the effort between kernel code and library code (different divisions might be appropriate on microkernels and monolithic kernels, for example). 3.1 New data structures The data structure declarations and symbol definitions for this API will appear in the header file . The API defines one new data structure: typedef struct ppsinfo { pps_seq_t sequence; /* event sequence # */ struct timespec timestamp; /* time of event */ int flags; /* flag bits */ } ppsinfo_t; The ``pps_seq_t'' type is an unsigned integer data type of at least 32 bits. The precise declaration of this type is system-dependent. --------- Note: the standard declaration for "struct timespec" is: typedef struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec_t; --------- The sequence number increases once per captured timestamp. Its initial value is undefined. If incremented past the largest unsigned long value, the next value is zero. --------- Note that the sequence number is most useful in applications where events other than PPS transitions are to be captured, Mogul, Mills, Brittenson [Page 5] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 which might be involved in a precision stopwatch application, for example. In such cases, the sequence number may be used to detect overruns, where the application has missed one or more events. It may also be used to detect an excessive event rate, or to detect that an event has failed to occur between two calls to the time_pps_fetch() function (defined later). --------- The timestamp field represents the value of the operating system's internal timebase when the timestamped occurred, or as close as possible to that time. The flag bits are: #define PPSFLAG_ASSERT 0x01 #define PPSFLAG_CLEAR 0x02 whose meanings are: PPSFLAG_ASSERT The timestamp was captured when the PPS signal was asserted (set to logical TRUE). PPSFLAG_CLEAR The timestamp was captured when the PPS signal was cleared (set to logical FALSE). 3.2 Mode bit definitions The API defines these mode bits: #define PPSMODE_NONE 0x00 #define PPSMODE_ONASSERT 0x01 #define PPSMODE_ONCLEAR 0x02 #define PPSMODE_ONBOTH (PPSMODE_ONASSERT|PPSMODE_ONCLEAR) #define PPSMODE_HARDPPS 0x04 whose meanings are: PPSMODE_NONE No timestamps will be captured. PPSMODE_ONASSERT Causes a timestamp to be captured when the PPS signal is asserted (set to logical TRUE). PPSMODE_ONCLEAR Causes a timestamp to be captured when the PPS signal is cleared (set to logical FALSE). PPSMODE_ONBOTH Causes a timestamp to be captured when the PPS signal changes states, in either direction. PPSMODE_HARDPPS Causes the most recently captured timestamp to be communicated to the operating system module that disciplines the system's internal timebase. Mogul, Mills, Brittenson [Page 6] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 The operating system will enforce two restrictions on the use of PPSMODE_HARDPPS: 1. It may be applied to at most one signal source at any given time. 2. It may only be set by a process with sufficient privileges to modify the system's internal timebase. (On UNIX systems, such modification is normally done using settimeofday() and/or adjtime(), and is restricted to users with superuser privilege.) If PPSMODE_HARDPPS is set, at least one of PPSMODE_ONASSERT or PPSMODE_ONCLEAR should also be set. Otherwise, the behavior of PPSMODE_HARDPPS is undefined. The operating system may implement all of these mode bits, or just a subset of them. If an attempt is made to set an unsupported mode bit, the API will return an error. 3.3 New functions In the description of functions that follows, we use the following function parameters: filedes A file descriptor (type: int), for a serial line or other source of PPS events. ppsinfobuf A record of type ``struct ppsinfo'', as defined in section 3.1. mode A set of mode bits (type: int), whose possible values are defined in section 3.2. 3.3.1 New functions: access to PPS events The API includes several functions use to enable or disable the use of a file descriptor for other PPS-related functions. SYNOPSIS int time_pps_enable(int filedes); int time_pps_disable(int filedes); DESCRIPTION Before an application can use any of the other PPS-related functions, it must first call time_pps_enable() on an already-open file descriptor for an appropriate special file. (The definition of what special files are appropriate for use with the PPS API is outside the scope of this specification, and may vary based on both operating Mogul, Mills, Brittenson [Page 7] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 system implementation, and local system configuration. The usual case is a serial line, whose DCD pin is connected to a source of PPS events.) After having successfully enabled the use of PPS events on a file descriptor, an application may call time_pps_disable() on that file descriptor. This stops the use of the PPS source for disciplining the system's timebase, if it had been configured to do so. The behavior of other functions in the PPS API is undefined, except when applied to a file descriptor after time_pps_enable() has been applied, and before time_pps_disable() has been applied. RETURN VALUES On successful completion, the time_pps_enable() and time_pps_disable() functions return 0. Otherwise, a value of -1 is returned and errno is set to indicate the error. ERRORS If the time_pps_enable() or time_pps_disable() function fails, errno may be set to one of the following values: [EBADF] The filedes parameter is not a valid file descriptor. [EOPNOTSUPP] The use of the PPS API is not supported for the file descriptor. [EPERM] The process's effective user ID does not have the required privileges to use the PPS API. 3.3.2 New functions: setting PPS mode bits The API includes several functions use to control the mode of a PPS-enabled file descriptor. SYNOPSIS int time_pps_setmode(int filedes, int mode); int time_pps_getmode(int filedes, int *mode); DESCRIPTION An application may use time_pps_setmode() to set the mode value for a PPS line. Mode bits are defined in section 3.2. An application may use time_pps_getmode() to discover the current settings of the PPS mode bits. An application that needs to change only a subset of the Mogul, Mills, Brittenson [Page 8] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 existing mode bits must first call time_pps_getmode() to obtain the current mode bit values, then set the new values using time_pps_setmode(). The default value for the mode bits is PPSMODE_NONE. RETURN VALUES On successful completion, the time_pps_setmode() and time_pps_getmode() functions return 0. Otherwise, a value of -1 is returned and errno is set to indicate the error. ERRORS If the time_pps_setmode() or time_pps_getmode() function fails, errno may be set to one of the following values: [EBADF] The filedes parameter is not a valid file descriptor. [EFAULT] A parameter points to an invalid address. [EOPNOTSUPP] The use of the PPS API is not supported for the file descriptor. [EINVAL] The operating system does not support all of the requested mode bits. [EPERM] The process's effective user ID does not have the required privileges to use the PPS API, or to set the given mode. 3.3.3 New functions: access to PPS timestamps The API includes one function that gives applications access to PPS timestamps. SYNOPSIS int time_pps_fetch(int filedes, struct ppsinfo *ppsinfobuf); DESCRIPTION An application may use time_pps_fetch() to obtain the most recent timestamp captured for the signal source corresponding to the filedes parameter. The result is left in the ppsinfobuf parameter, whose fields are defined in section 3.1. Mogul, Mills, Brittenson [Page 9] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 If this function is invoked before the system has captured a timestamp for the signal source, the ppsinfobuf returned will have its timespec field set to the POSIX base date (i.e., both the tv_sec and tv_nsec fields will be zero). RETURN VALUES On successful completion, the time_pps_fetch() function returns 0. Otherwise, a value of -1 is returned and errno is set to indicate the error. ERRORS If the time_pps_fetch() function fails, errno may be set to one of the following values: [EBADF] The filedes parameter is not a valid file descriptor. [EFAULT] A parameter points to an invalid address. [EOPNOTSUPP] The use of the PPS API is not supported for the file descriptor. 3.3.4 New functions: disciplining the kernel timebase The API does not include an explicit function for configuring the use of a PPS signal to discipline the operating system timebase. This is done using time_pps_setmode() and time_pps_getmode(). Warning: If this feature is configured for a special file that does not have an accurate 1-pulse-per-second signal, use of this feature may result in seriously incorrect timekeeping for the entire system. For best results, the 1-PPS signal should have much better frequency stability than the system's internal clock source (usually a crystal-controlled oscillator), and should have jitter (variation in interarrival time) much less than the system's clock-tick interval. See RFC1589 [3] for more information about how the system's timebase is disciplined using a PPS signal. 3.4 Example A typical use of this API might be: int fd; int mode; ppsinfo infobuf; /* Open a file descriptor and enable PPS on rising edges */ fd = open(PPSfilename, O_RDONLY, 0); Mogul, Mills, Brittenson [Page 10] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 time_pps_enable(fd); mode = PPSMODE_ONASSERT; time_pps_setmode(fd, mode); /* loop, printing the most recent timestamp every second or so */ while (1) { sleep(1); time_pps_fetch(fd, &infobuf); printf("Timestamp: %d.%09d, sequence: %ld\n", infobuf.timestamp.tv_sec, infobuf.timestamp.tv_nsec, infobuf.sequence); } Note that this example omits all of the error-checking that would be expected in a reliable program. 4 PPSDISC Line discipline One possible implementation of this API might be to define a new ``line discipline'' and then map the API onto a set of ioctl() commands. Here we sketch such an implementation; note that this is not part of the specification of the API, and applications should not expect this low-level interface to be available. In this approach, the set of line disciplines is augmented with one new line discipline, PPSDISC. This discipline will act exactly the same as the TTYDISC discipline, except for its handling of modem DCD interrupts. Once the TIOCSETD ioctl() has been used to select this line discipline, PPS-related operations on the serial line may be invoked using new ioctl() commands. For example (values used only for illustration): #define PPSGETTIME _IOR('t', 75, struct ppsinfo) #define PPSSETMODE _IOW('t', 76, int) #define PPSGETMODE _IOR('t', 77, int) 4.1 Example A typical use might be: int ldisc = PPSDISC; int ppsmode; struct ppsinfo ppsbuf; ioctl(fd, TIOCSETD, &ldisc); /* set discipline */ /* Mogul, Mills, Brittenson [Page 11] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 * Set this line to timestamp on a rising-edge interrupt, * and assign this line for the kernel hardpps() input */ mode = PPSMODE_ONASSERT | PPSMODE_HARDPPS; ioctl(fd, PPSSETMODE, &mode); sleep(2); /* allow time for the PPS pulse to happen */ /* obtain most recent timestamp and sequence # for this line */ ioctl(fd, PPSGETTIME, &ppsbuf); Again, this example imprudently omits any error-checking. 5 Security Considerations This API gives applications three capabilities: - Causing the system to capture timestamps on certain events. - Obtaining timestamps for certain events. - Affecting the system's internal timebase. The first capability should not affect security directly, but might cause a slight increase in interrupt latency and interrupt-handling overhead. The second capability might be useful in implementing certain kinds of covert communication channels. In most cases, neither of these first two issues is a significant security threat. The system administrator may prevent applications from using this API by simply using the traditional UNIX file protection facility to limit access to the relevant special files, so the risk inherent in providing the API is minimal. The final capability is reserved to highly privileged users. In UNIX systems, this means those with superuser privilege. Such users can evade protections based on file permissions; however, such users can in general cause unbounded havoc, and can set the internal timebase (and its rate of change), so this API creates no new vulnerabilities. 6 Acknowledgements The API in this document draws some of its inspiration from the LBL ``ppsclock'' distribution [1], originally implemented in 1993 by Steve McCanne, Craig Leres, and Van Jacobson. We also thank Craig Leres, Judah Levine, and Ulrich Windl for helpful comments they contributed during the drafting of this document. Mogul, Mills, Brittenson [Page 12] Internet-Draft Pulse-Per-Second API 12 January 1998 15:53 7 References 1. Steve McCanne, Craig Leres, and Van Jacobson. PPSCLOCK. ftp://ftp.ee.lbl.gov/ppsclock.tar.Z. 2. David L. Mills. Network Time Protocol (Version 3): Specification, Implementation and Analysis. RFC 1305, IETF, March, 1992. 3. David L. Mills. A Kernel Model for Precision Timekeeping. RFC 1589, IETF, March, 1994. 4. The Open Group. The Single UNIX Specification, Version 2 - 6 Vol Set for UNIX 98. Document number T912, The Open Group, February, 1997. 8 Authors' addresses Jeffrey C. Mogul Western Research Laboratory Digital Equipment Corporation 250 University Avenue Palo Alto, California, 94305, U.S.A. Email: mogul@wrl.dec.com Phone: 1 650 617 3304 (email preferred) David L. Mills Electrical Engineering Department University of Delaware Newark, DE 19716 Phone: (302) 831-8247 EMail: mills@udel.edu Jan Brittenson Sun Microsystems, Inc. 901 San Antonio Rd M/S MPK17-202 Palo Alto, CA 94303 Email: Jan.Brittenson@Eng.Sun.COM Mogul, Mills, Brittenson [Page 13]