Internet Engineering Task Force (IETF)                          D. Mills
Request for Comments: 5905                                   U. Delaware
Obsoletes: 1305, 4330                                     J. Martin, Ed.
Category: Standards Track                                            ISC
ISSN: 2070-1721                                               J. Burbank
                                                                W. Kasch
                                                                 JHU/APL
                                                               June 2010
        
Internet Engineering Task Force (IETF)                          D. Mills
Request for Comments: 5905                                   U. Delaware
Obsoletes: 1305, 4330                                     J. Martin, Ed.
Category: Standards Track                                            ISC
ISSN: 2070-1721                                               J. Burbank
                                                                W. Kasch
                                                                 JHU/APL
                                                               June 2010
        

Network Time Protocol Version 4: Protocol and Algorithms Specification

网络时间协议版本4:协议和算法规范

Abstract

摘要

The Network Time Protocol (NTP) is widely used to synchronize computer clocks in the Internet. This document describes NTP version 4 (NTPv4), which is backwards compatible with NTP version 3 (NTPv3), described in RFC 1305, as well as previous versions of the protocol. NTPv4 includes a modified protocol header to accommodate the Internet Protocol version 6 address family. NTPv4 includes fundamental improvements in the mitigation and discipline algorithms that extend the potential accuracy to the tens of microseconds with modern workstations and fast LANs. It includes a dynamic server discovery scheme, so that in many cases, specific server configuration is not required. It corrects certain errors in the NTPv3 design and implementation and includes an optional extension mechanism.

网络时间协议(NTP)广泛用于在Internet上同步计算机时钟。本文档描述了NTP版本4(NTPv4),它与RFC 1305中描述的NTP版本3(NTPv3)向后兼容,以及协议的先前版本。NTPv4包括一个修改后的协议头,以适应Internet协议版本6地址系列。NTPv4包括缓解和规范算法的根本改进,通过现代工作站和快速局域网将潜在精度扩展到数十微秒。它包括一个动态服务器发现方案,因此在许多情况下,不需要特定的服务器配置。它纠正了NTPv3设计和实现中的某些错误,并包括可选的扩展机制。

Status of This Memo

关于下段备忘

This is an Internet Standards Track document.

这是一份互联网标准跟踪文件。

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 5741.

本文件是互联网工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经接受了公众审查,并已被互联网工程指导小组(IESG)批准出版。有关互联网标准的更多信息,请参见RFC 5741第2节。

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://www.rfc-editor.org/info/rfc5905.

有关本文件当前状态、任何勘误表以及如何提供反馈的信息,请访问http://www.rfc-editor.org/info/rfc5905.

Copyright Notice

版权公告

Copyright (c) 2010 IETF Trust and the persons identified as the document authors. All rights reserved.

版权所有(c)2010 IETF信托基金和确定为文件作者的人员。版权所有。

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

本文件受BCP 78和IETF信托有关IETF文件的法律规定的约束(http://trustee.ietf.org/license-info)自本文件出版之日起生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件中提取的代码组件必须包括信托法律条款第4.e节中所述的简化BSD许可证文本,并提供简化BSD许可证中所述的无担保。

This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English.

本文件可能包含2008年11月10日之前发布或公开的IETF文件或IETF贡献中的材料。控制某些材料版权的人员可能未授予IETF信托允许在IETF标准流程之外修改此类材料的权利。在未从控制此类材料版权的人员处获得充分许可的情况下,不得在IETF标准流程之外修改本文件,也不得在IETF标准流程之外创建其衍生作品,除了将其格式化以RFC形式发布或将其翻译成英语以外的其他语言。

Table of Contents

目录

   1. Introduction ....................................................4
      1.1. Requirements Notation ......................................5
   2. Modes of Operation ..............................................6
   3. Protocol Modes ..................................................6
      3.1. Dynamic Server Discovery ...................................7
   4. Definitions .....................................................8
   5. Implementation Model ...........................................10
   6. Data Types .....................................................12
   7. Data Structures ................................................16
      7.1. Structure Conventions .....................................16
      7.2. Global Parameters .........................................16
      7.3. Packet Header Variables ...................................17
      7.4. The Kiss-o'-Death Packet ..................................24
      7.5. NTP Extension Field Format ................................25
   8. On-Wire Protocol ...............................................26
   9. Peer Process ...................................................30
      9.1. Peer Process Variables ....................................31
      9.2. Peer Process Operations ...................................33
   10. Clock Filter Algorithm ........................................37
        
   1. Introduction ....................................................4
      1.1. Requirements Notation ......................................5
   2. Modes of Operation ..............................................6
   3. Protocol Modes ..................................................6
      3.1. Dynamic Server Discovery ...................................7
   4. Definitions .....................................................8
   5. Implementation Model ...........................................10
   6. Data Types .....................................................12
   7. Data Structures ................................................16
      7.1. Structure Conventions .....................................16
      7.2. Global Parameters .........................................16
      7.3. Packet Header Variables ...................................17
      7.4. The Kiss-o'-Death Packet ..................................24
      7.5. NTP Extension Field Format ................................25
   8. On-Wire Protocol ...............................................26
   9. Peer Process ...................................................30
      9.1. Peer Process Variables ....................................31
      9.2. Peer Process Operations ...................................33
   10. Clock Filter Algorithm ........................................37
        
   11. System Process ................................................39
      11.1. System Process Variables .................................40
      11.2. System Process Operations ................................41
           11.2.1. Selection Algorithm ...............................43
           11.2.2. Cluster Algorithm .................................44
           11.2.3. Combine Algorithm .................................45
      11.3. Clock Discipline Algorithm ...............................47
   12. Clock-Adjust Process ..........................................51
   13. Poll Process ..................................................51
      13.1. Poll Process Variables ...................................51
      13.2. Poll Process Operations ..................................52
   14. Simple Network Time Protocol (SNTP) ...........................54
   15. Security Considerations .......................................55
   16. IANA Considerations ...........................................58
   17. Acknowledgements ..............................................59
   18. References ....................................................59
      18.1. Normative References .....................................59
      18.2. Informative References ...................................59
   Appendix A.  Code Skeleton  .......................................61
     A.1.  Global Definitions  .......................................61
       A.1.1. Definitions, Constants, Parameters .....................61
       A.1.2. Packet Data Structures .................................65
       A.1.3. Association Data Structures ............................66
       A.1.4. System Data Structures .................................68
       A.1.5. Local Clock Data Structures ............................69
       A.1.6. Function Prototypes ....................................69
     A.2. Main Program and Utility Routines ..........................70
     A.3. Kernel Input/Output Interface ..............................73
     A.4. Kernel System Clock Interface ..............................74
     A.5. Peer Process ...............................................76
       A.5.1. receive() ..............................................77
       A.5.2. clock_filter() .........................................85
       A.5.3. fast_xmit() ............................................88
       A.5.4. access() ...............................................89
       A.5.5. System Process .........................................90
       A.5.6. Clock Adjust Process ..................................103
       A.5.7. Poll Process ..........................................104
        
   11. System Process ................................................39
      11.1. System Process Variables .................................40
      11.2. System Process Operations ................................41
           11.2.1. Selection Algorithm ...............................43
           11.2.2. Cluster Algorithm .................................44
           11.2.3. Combine Algorithm .................................45
      11.3. Clock Discipline Algorithm ...............................47
   12. Clock-Adjust Process ..........................................51
   13. Poll Process ..................................................51
      13.1. Poll Process Variables ...................................51
      13.2. Poll Process Operations ..................................52
   14. Simple Network Time Protocol (SNTP) ...........................54
   15. Security Considerations .......................................55
   16. IANA Considerations ...........................................58
   17. Acknowledgements ..............................................59
   18. References ....................................................59
      18.1. Normative References .....................................59
      18.2. Informative References ...................................59
   Appendix A.  Code Skeleton  .......................................61
     A.1.  Global Definitions  .......................................61
       A.1.1. Definitions, Constants, Parameters .....................61
       A.1.2. Packet Data Structures .................................65
       A.1.3. Association Data Structures ............................66
       A.1.4. System Data Structures .................................68
       A.1.5. Local Clock Data Structures ............................69
       A.1.6. Function Prototypes ....................................69
     A.2. Main Program and Utility Routines ..........................70
     A.3. Kernel Input/Output Interface ..............................73
     A.4. Kernel System Clock Interface ..............................74
     A.5. Peer Process ...............................................76
       A.5.1. receive() ..............................................77
       A.5.2. clock_filter() .........................................85
       A.5.3. fast_xmit() ............................................88
       A.5.4. access() ...............................................89
       A.5.5. System Process .........................................90
       A.5.6. Clock Adjust Process ..................................103
       A.5.7. Poll Process ..........................................104
        
1. Introduction
1. 介绍

This document defines the Network Time Protocol version 4 (NTPv4), which is widely used to synchronize system clocks among a set of distributed time servers and clients. It describes the core architecture, protocol, state machines, data structures, and algorithms. NTPv4 introduces new functionality to NTPv3, as described in [RFC1305], and functionality expanded from Simple NTP version 4 (SNTPv4) as described in [RFC4330] (SNTPv4 is a subset of NTPv4). This document obsoletes [RFC1305] and [RFC4330]. While certain minor changes have been made in some protocol header fields, these do not affect the interoperability between NTPv4 and previous versions of NTP and SNTP.

本文档定义了网络时间协议版本4(NTPv4),广泛用于同步一组分布式时间服务器和客户端之间的系统时钟。它描述了核心架构、协议、状态机、数据结构和算法。如[RFC1305]所述,NTPv4为NTPv3引入了新功能,并从简单NTP版本4(SNTPv4)扩展了功能,如[RFC4330]所述(SNTPv4是NTPv4的子集)。本文件废除了[RFC1305]和[RFC4330]。虽然在某些协议头字段中进行了某些细微的更改,但这些更改不会影响NTPv4与以前版本的NTP和SNTP之间的互操作性。

The NTP subnet model includes a number of widely accessible primary time servers synchronized by wire or radio to national standards. The purpose of the NTP protocol is to convey timekeeping information from these primary servers to secondary time servers and clients via both private networks and the public Internet. Precisely tuned algorithms mitigate errors that may result from network disruptions, server failures, and possible hostile actions. Servers and clients are configured such that values flow towards clients from the primary servers at the root via branching secondary servers.

NTP子网模型包括许多可广泛访问的主时间服务器,这些服务器通过有线或无线方式按照国家标准同步。NTP协议的目的是通过专用网络和公共互联网将计时信息从这些主服务器传送到辅助计时服务器和客户端。经过精确调整的算法可以减少网络中断、服务器故障和可能的恶意操作可能导致的错误。服务器和客户端的配置使得值通过分支辅助服务器从根目录下的主服务器流向客户端。

The NTPv4 design overcomes significant shortcomings in the NTPv3 design, corrects certain bugs, and incorporates new features. In particular, expanded NTP timestamp definitions encourage the use of the floating double data type throughout the implementation. As a result, the time resolution is better than one nanosecond, and frequency resolution is less than one nanosecond per second. Additional improvements include a new clock discipline algorithm that is more responsive to system clock hardware frequency fluctuations. Typical primary servers using modern machines are precise within a few tens of microseconds. Typical secondary servers and clients on fast LANs are within a few hundred microseconds with poll intervals up to 1024 seconds, which was the maximum with NTPv3. With NTPv4, servers and clients are precise within a few tens of milliseconds with poll intervals up to 36 hours.

NTPv4设计克服了NTPv3设计中的重大缺陷,纠正了某些错误,并融入了新功能。特别是,扩展的NTP时间戳定义鼓励在整个实现中使用浮动双精度数据类型。结果,时间分辨率优于1纳秒,频率分辨率小于1纳秒/秒。其他改进包括一种新的时钟规程算法,该算法对系统时钟硬件频率波动更具响应性。使用现代机器的典型主服务器精确到几十微秒。快速局域网上的典型辅助服务器和客户端在几百微秒之内,轮询间隔高达1024秒,这是NTPv3的最大值。有了NTPv4,服务器和客户机在几十毫秒内就可以实现精确查询,轮询间隔最长可达36小时。

The main body of this document describes the core protocol and data structures necessary to interoperate between conforming implementations. Appendix A contains a full-featured example in the form of a skeleton program, including data structures and code segments for the core algorithms as well as the mitigation algorithms used to enhance reliability and accuracy. While the skeleton program and other descriptions in this document apply to a particular implementation, they are not intended as the only way the required functions can be implemented. The contents of Appendix A are non-

本文档的主体部分描述了在一致性实现之间进行互操作所需的核心协议和数据结构。附录A以框架程序的形式包含一个功能齐全的示例,包括核心算法的数据结构和代码段,以及用于提高可靠性和准确性的缓解算法。虽然本文档中的框架程序和其他描述适用于特定的实现,但它们并不是实现所需功能的唯一方式。附录A的内容是非强制性的-

normative examples designed to illustrate the protocol's operation and are not a requirement for a conforming implementation. While the NTPv3 symmetric key authentication scheme described in this document has been carried over from NTPv3, the Autokey public key authentication scheme new to NTPv4 is described in [RFC5906].

设计用于说明协议操作的规范性示例,不是一致性实现的要求。虽然本文档中描述的NTPv3对称密钥认证方案是从NTPv3继承而来的,但[RFC5906]中描述了NTPv4新的自动密钥公钥认证方案。

The NTP protocol includes modes of operation described in Section 2 using data types described in Section 6 and data structures described in Section 7. The implementation model described in Section 5 is based on a threaded, multi-process architecture, although other architectures could be used as well. The on-wire protocol described in Section 8 is based on a returnable-time design that depends only on measured clock offsets, but does not require reliable message delivery. Reliable message delivery such as TCP [RFC0793] can actually make the delivered NTP packet less reliable since retries would increase the delay value and other errors. The synchronization subnet is a self-organizing, hierarchical, master-slave network with synchronization paths determined by a shortest-path spanning tree and defined metric. While multiple masters (primary servers) may exist, there is no requirement for an election protocol.

NTP协议包括第2节中描述的操作模式,使用第6节中描述的数据类型和第7节中描述的数据结构。第5节中描述的实现模型基于线程化的多进程体系结构,尽管也可以使用其他体系结构。第8节中描述的在线协议基于可返回时间设计,该设计仅取决于测量的时钟偏移,但不要求可靠的消息传递。可靠的消息传递(如TCP[RFC0793])实际上会降低传递的NTP数据包的可靠性,因为重试会增加延迟值和其他错误。同步子网是一个自组织、分层的主从网络,同步路径由最短路径生成树和定义的度量确定。虽然可能存在多个主服务器(主服务器),但不需要选择协议。

This document includes material from [ref9], which contains flow charts and equations unsuited for RFC format. There is much additional information in [ref7], including an extensive technical analysis and performance assessment of the protocol and algorithms in this document. The reference implementation is available at www.ntp.org.

本文件包括[ref9]中的材料,其中包含不适合RFC格式的流程图和方程式。参考文献7中有许多附加信息,包括本文中对协议和算法的广泛技术分析和性能评估。参考实施可在www.ntp.org上获得。

The remainder of this document contains numerous variables and mathematical expressions. Some variables take the form of Greek characters, which are spelled out by their full case-sensitive name. For example, DELTA refers to the uppercase Greek character, while delta refers to the lowercase character. Furthermore, subscripts are denoted with '_'; for example, theta_i refers to the lowercase Greek character theta with subscript i, or phonetically theta sub i. In this document, all time values are in seconds (s), and all frequencies will be specified as fractional frequency offsets (FFOs) (pure number). It is often convenient to express these FFOs in parts per million (ppm).

本文档的其余部分包含许多变量和数学表达式。一些变量采用希腊字符的形式,由其区分大小写的全名拼写。例如,DELTA表示大写希腊字符,而DELTA表示小写字符。此外,下标用‘’表示;例如,theta_i指的是带有下标i的小写希腊字符theta,或者是语音上的theta sub i。在本文件中,所有时间值均以秒为单位,所有频率将指定为分数频率偏移(FFO)(纯数字)。用百万分之一(ppm)表示这些FFO通常很方便。

1.1. Requirements Notation
1.1. 需求符号

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

本文件中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“应”、“不应”、“建议”、“可”和“可选”应按照[RFC2119]中所述进行解释。

2. Modes of Operation
2. 运作模式

An NTP implementation operates as a primary server, secondary server, or client. A primary server is synchronized to a reference clock directly traceable to UTC (e.g., GPS, Galileo, etc.). A client synchronizes to one or more upstream servers, but does not provide synchronization to dependent clients. A secondary server has one or more upstream servers and one or more downstream servers or clients. All servers and clients who are fully NTPv4-compliant MUST implement the entire suite of algorithms described in this document. In order to maintain stability in large NTP subnets, secondary servers SHOULD be fully NTPv4-compliant. Alternative algorithms MAY be used, but their output MUST be identical to the algorithms described in this specification.

NTP实现作为主服务器、辅助服务器或客户端运行。主服务器与可直接追溯到UTC的参考时钟同步(如GPS、Galileo等)。客户端与一个或多个上游服务器同步,但不向依赖客户端提供同步。辅助服务器具有一个或多个上游服务器和一个或多个下游服务器或客户端。所有完全符合NTPv4的服务器和客户端必须实现本文档中描述的整套算法。为了在大型NTP子网中保持稳定性,辅助服务器应完全符合NTPv4。可以使用替代算法,但其输出必须与本规范中描述的算法相同。

3. Protocol Modes
3. 协议模式

There are three NTP protocol variants: symmetric, client/server, and broadcast. Each is associated with an association mode (a description of the relationship between two NTP speakers) as shown in Figure 1. In addition, persistent associations are mobilized upon startup and are never demobilized. Ephemeral associations are mobilized upon the arrival of a packet and are demobilized upon error or timeout.

NTP协议有三种变体:对称、客户端/服务器和广播。每个都与关联模式(两个NTP扬声器之间关系的描述)关联,如图1所示。此外,持久性关联在启动时被动员,并且永远不会被遣散。临时关联在数据包到达时被激活,在出错或超时时被解除。

          +-------------------+-------------------+------------------+
          |  Association Mode | Assoc. Mode Value | Packet Mode Value|
          +-------------------+-------------------+------------------+
          | Symmetric Active  |         1         | 1 or 2           |
          | Symmetric Passive |         2         | 1                |
          | Client            |         3         | 4                |
          | Server            |         4         | 3                |
          | Broadcast Server  |         5         | 5                |
          | Broadcast Client  |         6         | N/A              |
          +-------------------+-------------------+------------------+
        
          +-------------------+-------------------+------------------+
          |  Association Mode | Assoc. Mode Value | Packet Mode Value|
          +-------------------+-------------------+------------------+
          | Symmetric Active  |         1         | 1 or 2           |
          | Symmetric Passive |         2         | 1                |
          | Client            |         3         | 4                |
          | Server            |         4         | 3                |
          | Broadcast Server  |         5         | 5                |
          | Broadcast Client  |         6         | N/A              |
          +-------------------+-------------------+------------------+
        

Figure 1: Association and Packet Modes

图1:关联和数据包模式

In the client/server variant, a persistent client sends packet mode 4 packets to a server, which returns packet mode 3 packets. Servers provide synchronization to one or more clients, but do not accept synchronization from them. A server can also be a reference clock driver that obtains time directly from a standard source such as a GPS receiver or telephone modem service. In this variant, clients pull synchronization from servers.

在客户机/服务器变体中,持久化客户机向服务器发送数据包模式4数据包,服务器返回数据包模式3数据包。服务器向一个或多个客户端提供同步,但不接受来自它们的同步。服务器也可以是直接从标准源(如GPS接收器或电话调制解调器服务)获取时间的参考时钟驱动器。在这个变体中,客户端从服务器获取同步。

In the symmetric variant, a peer operates as both a server and client using either a symmetric active or symmetric passive association. A persistent symmetric active association sends symmetric active (mode 1) packets to a symmetric active peer association. Alternatively, an ephemeral symmetric passive association can be mobilized upon the arrival of a symmetric active packet with no matching association. That association sends symmetric passive (mode 2) packets and persists until error or timeout. Peers both push and pull synchronization to and from each other. For the purposes of this document, a peer operates like a client, so references to client imply peer as well.

在对称变体中,对等机使用对称主动或对称被动关联同时作为服务器和客户端运行。持久对称活动关联向对称活动对等关联发送对称活动(模式1)数据包。或者,可以在没有匹配关联的对称主动分组到达时动员短暂对称被动关联。该关联发送对称被动(模式2)数据包,并持续到错误或超时。对等点相互推送和拉送同步。在本文档中,对等机的操作与客户端类似,因此对客户端的引用也意味着对等机。

In the broadcast variant, a persistent broadcast server association sends periodic broadcast server (mode 5) packets that can be received by multiple clients. Upon reception of a broadcast server packet without a matching association, an ephemeral broadcast client (mode 6) association is mobilized and persists until error or timeout. It is useful to provide an initial volley where the client operating in client mode exchanges several packets with the server, so as to calibrate the propagation delay and to run the Autokey security protocol, after which the client reverts to broadcast client mode. A broadcast server pushes synchronization to clients and other servers.

在广播变体中,持久广播服务器关联发送可由多个客户端接收的周期性广播服务器(模式5)数据包。在接收到没有匹配关联的广播服务器分组时,临时广播客户端(模式6)关联被激活并持续到错误或超时。在客户端模式下运行的客户端与服务器交换多个数据包时,提供初始截击是有用的,以便校准传播延迟并运行自动密钥安全协议,然后客户端恢复到广播客户端模式。广播服务器将同步推送到客户端和其他服务器。

Loosely following the conventions established by the telephone industry, the level of each server in the hierarchy is defined by a stratum number. Primary servers are assigned stratum one; secondary servers at each lower level are assigned stratum numbers one greater than the preceding level. As the stratum number increases, its accuracy degrades depending on the particular network path and system clock stability. Mean errors, measured by synchronization distances, increase approximately in proportion to stratum numbers and measured round-trip delay.

松散地遵循电话行业建立的约定,层次结构中每个服务器的级别由一个层编号定义。主服务器被分配到第一层;为每个较低级别的辅助服务器分配比上一级别大一个的层编号。随着层数的增加,其精度会因特定的网络路径和系统时钟稳定性而降低。通过同步距离测量的平均误差与地层数量和测量的往返延迟近似成比例增加。

As a standard practice, timing network topology should be organized to avoid timing loops and minimize the synchronization distance. In NTP, the subnet topology is determined using a variant of the Bellman-Ford distributed routing algorithm, which computes the shortest-path spanning tree rooted on the primary servers. As a result of this design, the algorithm automatically reorganizes the subnet, so as to produce the most accurate and reliable time, even when there are failures in the timing network.

作为一种标准实践,定时网络拓扑结构应组织为避免定时环路并最小化同步距离。在NTP中,子网拓扑是使用Bellman-Ford分布式路由算法的一种变体来确定的,该算法计算以主服务器为根的最短路径生成树。由于这种设计,该算法自动重新组织子网,以便产生最准确和可靠的时间,即使在定时网络出现故障时也是如此。

3.1. Dynamic Server Discovery
3.1. 动态服务器发现

There are two special associations, manycast client and manycast server, which provide a dynamic server discovery function. There are two types of manycast client associations: persistent and ephemeral. The persistent manycast client sends client (mode 3) packets to a

有两个特殊的关联,manycast客户端和manycast服务器,它们提供了动态服务器发现功能。有两种类型的manycast客户机关联:持久的和短暂的。持久性manycast客户端将客户端(模式3)数据包发送到

designated IPv4 or IPv6 broadcast or multicast group address. Designated manycast servers within range of the time-to-live (TTL) field in the packet header listen for packets with that address. If a server is suitable for synchronization, it returns an ordinary server (mode 4) packet using the client's unicast address. Upon receiving this packet, the client mobilizes an ephemeral client (mode 3) association. The ephemeral client association persists until error or timeout.

指定的IPv4或IPv6广播或多播组地址。在数据包头中的生存时间(TTL)字段范围内指定的多播服务器侦听具有该地址的数据包。如果服务器适合同步,它将使用客户端的单播地址返回普通服务器(模式4)数据包。在接收到该数据包后,客户机移动临时客户机(模式3)关联。短暂的客户端关联将持续存在,直到出现错误或超时。

A manycast client continues sending packets to search for a minimum number of associations. It starts with a TTL equal to one and continuously adding one to it until the minimum number of associations is made or when the TTL reaches a maximum value. If the TTL reaches its maximum value and yet not enough associations are mobilized, the client stops transmission for a time-out period to clear all associations, and then repeats the search cycle. If a minimum number of associations has been mobilized, then the client starts transmitting one packet per time-out period to maintain the associations. Field constraints limit the minimum value to 1 and the maximum to 255. These limits may be tuned for individual application needs.

manycast客户端继续发送数据包以搜索最少数量的关联。它从一个等于1的TTL开始,并不断地向其中添加一个,直到产生最小的关联数或TTL达到最大值。如果TTL达到其最大值,但未激活足够的关联,则客户端会在超时期间停止传输以清除所有关联,然后重复搜索周期。如果已经动员了最少数量的关联,则客户端开始在每个超时期间发送一个数据包以维护关联。字段约束将最小值限制为1,最大值限制为255。这些限制可根据个别应用需要进行调整。

The ephemeral associations compete among themselves. As new ephemeral associations are mobilized, the client runs the mitigation algorithms described in Sections 10 and 11.2 for the best candidates out of the population, the remaining ephemeral associations are timed out and demobilized. In this way, the population includes only the best candidates that have most recently responded with an NTP packet to discipline the system clock.

短暂的协会相互竞争。当新的临时关联被动员时,客户运行第10节和第11.2节中描述的缓解算法,对于人口中的最佳候选,剩余的临时关联将超时并复员。这样,总体只包括最近响应NTP数据包以调节系统时钟的最佳候选。

4. Definitions
4. 定义

A number of technical terms are defined in this section. A timescale is a frame of reference where time is expressed as the value of a monotonically increasing binary counter with an indefinite number of bits. It counts in seconds and fractions of a second, when a decimal point is employed. The Coordinated Universal Time (UTC) timescale is defined by ITU-R TF.460 [ITU-R_TF.460]. Under the auspices of the Metre Convention of 1865, in 1975 the CGPM [CGPM] strongly endorsed the use of UTC as the basis for civil time.

本节定义了许多技术术语。时间刻度是一个参考帧,其中时间表示为具有不定位数的单调递增二进制计数器的值。当使用小数点时,它以秒和一秒的分数计算。协调世界时(UTC)时标由ITU-R TF.460[ITU-R_TF.460]定义。在1865年米制公约的支持下,1975年,CGPM(CGPM)强烈支持使用UTC作为民用时间的基础。

The Coordinated Universal Time (UTC) timescale represents mean solar time as disseminated by national standards laboratories. The system time is represented by the system clock maintained by the hardware and operating system. The goal of the NTP algorithms is to minimize both the time difference and frequency difference between UTC and the system clock. When these differences have been reduced below nominal tolerances, the system clock is said to be synchronized to UTC.

协调世界时(UTC)时标表示国家标准实验室发布的平均太阳时。系统时间由硬件和操作系统维护的系统时钟表示。NTP算法的目标是最小化UTC和系统时钟之间的时差和频率差。当这些差异降低到标称公差以下时,系统时钟被称为与UTC同步。

The date of an event is the UTC time at which the event takes place. Dates are ephemeral values designated with uppercase T. Running time is another timescale that is coincident to the synchronization function of the NTP program.

事件日期是事件发生的UTC时间。日期是用大写字母T指定的短暂值。运行时间是与NTP程序的同步功能一致的另一个时间刻度。

A timestamp T(t) represents either the UTC date or time offset from UTC at running time t. Which meaning is intended should be clear from the context. Let T(t) be the time offset, R(t) the frequency offset, and D(t) the aging rate (first derivative of R(t) with respect to t). Then, if T(t_0) is the UTC time offset determined at t = t_0, the UTC time offset at time t is

时间戳T(T)表示UTC日期或运行时间T与UTC的时间偏移。应该从上下文中清楚地知道要表达什么意思。设T(T)为时间偏移,R(T)为频率偏移,D(T)为老化率(R(T)对T的一阶导数)。然后,如果T(T_0)是在T=T_0时确定的UTC时间偏移,则在T时的UTC时间偏移为

T(t) = T(t_0) + R(t_0)(t-t_0) + 1/2 * D(t_0)(t-t_0)^2 + e,

T(T)=T(T_0)+R(T_0)(T-T_0)+1/2*D(T_0)(T-T_0)^2+e,

where e is a stochastic error term discussed later in this document. While the D(t) term is important when characterizing precision oscillators, it is ordinarily neglected for computer oscillators. In this document, all time values are in seconds (s) and all frequency values are in seconds-per-second (s/s). It is sometimes convenient to express frequency offsets in parts-per-million (ppm), where 1 ppm is equal to 10^(-6) s/s.

其中e是本文后面讨论的随机误差项。当描述精密振荡器时,D(t)项很重要,但对于计算机振荡器,它通常被忽略。在本文档中,所有时间值均以秒为单位,所有频率值均以秒/秒为单位。有时可以方便地用百万分之一(ppm)表示频率偏移,其中1ppm等于10^(-6)s/s。

It is important in computer timekeeping applications to assess the performance of the timekeeping function. The NTP performance model includes four statistics that are updated each time a client makes a measurement with a server. The offset (theta) represents the maximum-likelihood time offset of the server clock relative to the system clock. The delay (delta) represents the round-trip delay between the client and server. The dispersion (epsilon) represents the maximum error inherent in the measurement. It increases at a rate equal to the maximum disciplined system clock frequency tolerance (PHI), typically 15 ppm. The jitter (psi) is defined as the root-mean-square (RMS) average of the most recent offset differences, and it represents the nominal error in estimating the offset.

在计算机计时应用中,评估计时功能的性能非常重要。NTP性能模型包括四个统计信息,每次客户端对服务器进行测量时都会更新这些统计信息。偏移量(θ)表示服务器时钟相对于系统时钟的最大似然时间偏移量。延迟(delta)表示客户端和服务器之间的往返延迟。色散(ε)表示测量中固有的最大误差。它以等于最大纪律系统时钟频率容差(φ)的速率增加,通常为15 ppm。抖动(psi)定义为最近偏移差的均方根(RMS)平均值,它表示估计偏移时的标称误差。

While the theta, delta, epsilon, and psi statistics represent measurements of the system clock relative to each server clock separately, the NTP protocol includes mechanisms to combine the statistics of several servers to more accurately discipline and calibrate the system clock. The system offset (THETA) represents the maximum-likelihood offset estimate for the server population. The system jitter (PSI) represents the nominal error in estimating the system offset. The delta and epsilon statistics are accumulated at each stratum level from the reference clock to produce the root delay (DELTA) and root dispersion (EPSILON) statistics. The synchronization distance (LAMBDA) equal to EPSILON + DELTA / 2 represents the maximum error due to all causes. The detailed

虽然θ、δ、ε和psi统计数据分别表示相对于每个服务器时钟的系统时钟测量值,但NTP协议包括组合多个服务器统计数据的机制,以更准确地调整和校准系统时钟。系统偏移量(θ)表示服务器总体的最大似然偏移量估计。系统抖动(PSI)表示估计系统偏移时的标称误差。增量和ε统计信息从参考时钟在每个层级累积,以产生根延迟(增量)和根分散(ε)统计信息。同步距离(λ)等于ε+δ/2表示所有原因导致的最大误差。详细的

formulations of these statistics are given in Section 11.2. They are available to the dependent applications in order to assess the performance of the synchronization function.

第11.2节给出了这些统计数据的公式。它们可供相关应用程序使用,以评估同步功能的性能。

5. Implementation Model
5. 实现模型

Figure 2 shows the architecture of a typical, multi-threaded implementation. It includes two processes dedicated to each server, a peer process to receive messages from the server or reference clock, and a poll process to transmit messages to the server or reference clock.

图2显示了一个典型的多线程实现的体系结构。它包括两个专用于每台服务器的进程,一个从服务器或参考时钟接收消息的对等进程,以及一个向服务器或参考时钟发送消息的轮询进程。

   .....................................................................
   . Remote   .   Peer/Poll  .              System          .  Clock   .
   . Servers  .   Processes  .              Process         .Discipline.
   .          .              .                              . Process  .
   .+--------+. +-----------+. +------------+               .          .
   .|        |->|           |. |            |               .          .
   .|Server 1|  |Peer/Poll 1|->|            |               .          .
   .|        |<-|           |. |            |               .          .
   .+--------+. +-----------+. |            |               .          .
   .          .       ^      . |            |               .          .
   .          .       |      . |            |               .          .
   .+--------+. +-----------+. |            |  +-----------+.          .
   .|        |->|           |. | Selection  |->|           |. +------+ .
   .|Server 2|  |Peer/Poll 2|->|    and     |  | Combine   |->| Loop | .
   .|        |<-|           |. | Cluster    |  | Algorithm |. |Filter| .
   .+--------+. +-----------+. | Algorithms |->|           |. +------+ .
   .          .       ^      . |            |  +-----------+.    |     .
   .          .       |      . |            |               .    |     .
   .+--------+. +-----------+. |            |               .    |     .
   .|        |->|           |. |            |               .    |     .
   .|Server 3|  |Peer/Poll 3|->|            |               .    |     .
   .|        |<-|           |. |            |               .    |     .
   .+--------+. +-----------+. +------------+               .    |     .
   ....................^.........................................|......
                       |                                    .    V     .
                       |                                    . +-----+  .
                       +--------------------------------------| VFO |  .
                                                            . +-----+  .
                                                            .  Clock   .
                                                            .  Adjust  .
                                                            .  Process .
                                                            ............
        
   .....................................................................
   . Remote   .   Peer/Poll  .              System          .  Clock   .
   . Servers  .   Processes  .              Process         .Discipline.
   .          .              .                              . Process  .
   .+--------+. +-----------+. +------------+               .          .
   .|        |->|           |. |            |               .          .
   .|Server 1|  |Peer/Poll 1|->|            |               .          .
   .|        |<-|           |. |            |               .          .
   .+--------+. +-----------+. |            |               .          .
   .          .       ^      . |            |               .          .
   .          .       |      . |            |               .          .
   .+--------+. +-----------+. |            |  +-----------+.          .
   .|        |->|           |. | Selection  |->|           |. +------+ .
   .|Server 2|  |Peer/Poll 2|->|    and     |  | Combine   |->| Loop | .
   .|        |<-|           |. | Cluster    |  | Algorithm |. |Filter| .
   .+--------+. +-----------+. | Algorithms |->|           |. +------+ .
   .          .       ^      . |            |  +-----------+.    |     .
   .          .       |      . |            |               .    |     .
   .+--------+. +-----------+. |            |               .    |     .
   .|        |->|           |. |            |               .    |     .
   .|Server 3|  |Peer/Poll 3|->|            |               .    |     .
   .|        |<-|           |. |            |               .    |     .
   .+--------+. +-----------+. +------------+               .    |     .
   ....................^.........................................|......
                       |                                    .    V     .
                       |                                    . +-----+  .
                       +--------------------------------------| VFO |  .
                                                            . +-----+  .
                                                            .  Clock   .
                                                            .  Adjust  .
                                                            .  Process .
                                                            ............
        

Figure 2: Implementation Model

图2:实现模型

These processes operate on a common data structure, called an association, which contains the statistics described above along with various other data described in Section 9. A client sends packets to one or more servers and then processes returned packets when they are received. The server interchanges source and destination addresses and ports, overwrites certain fields in the packet and returns it immediately (in the client/server mode) or at some time later (in the symmetric modes). As each NTP message is received, the offset theta between the peer clock and the system clock is computed along with the associated statistics delta, epsilon, and psi.

这些过程在称为关联的公共数据结构上运行,该结构包含上述统计信息以及第9节中描述的各种其他数据。客户端将数据包发送到一个或多个服务器,然后在接收到返回的数据包时对其进行处理。服务器交换源地址、目标地址和端口,覆盖数据包中的某些字段,并立即(在客户机/服务器模式下)或稍后(在对称模式下)返回数据包。当接收到每个NTP消息时,计算对等时钟和系统时钟之间的偏移θ以及相关的统计数据δ、ε和psi。

The system process includes the selection, cluster, and combine algorithms that mitigate among the various servers and reference clocks to determine the most accurate and reliable candidates to synchronize the system clock. The selection algorithm uses Byzantine fault detection principles to discard the presumably incorrect candidates called "falsetickers" from the incident population, leaving only good candidates called "truechimers". A truechimer is a clock that maintains timekeeping accuracy to a previously published and trusted standard, while a falseticker is a clock that shows misleading or inconsistent time. The cluster algorithm uses statistical principles to find the most accurate set of truechimers. The combine algorithm computes the final clock offset by statistically averaging the surviving truechimers.

系统过程包括选择、集群和组合算法,这些算法在各种服务器和参考时钟之间进行缓解,以确定同步系统时钟的最准确和可靠的候选者。选择算法使用拜占庭式故障检测原理,从事件总体中丢弃可能不正确的候选对象(称为“Falstickers”),只留下良好的候选对象(称为“truechimers”)。truechimer是一种将计时精度保持在先前发布的可信标准的时钟,而Falsticker是一种显示误导性或不一致时间的时钟。聚类算法使用统计原理来寻找最准确的真嵌合体集。联合算法通过统计平均幸存的TrueChimer来计算最终时钟偏移。

The clock discipline process is a system process that controls the time and frequency of the system clock, here represented as a variable frequency oscillator (VFO). Timestamps struck from the VFO close the feedback loop that maintains the system clock time. Associated with the clock discipline process is the clock-adjust process, which runs once each second to inject a computed time offset and maintain constant frequency. The RMS average of past time offset differences represents the nominal error or system clock jitter. The RMS average of past frequency offset differences represents the oscillator frequency stability or frequency wander. These terms are given precise interpretation in Section 11.3.

时钟规程过程是控制系统时钟的时间和频率的系统过程,这里表示为变频振荡器(VFO)。从VFO发出的时间戳关闭维持系统时钟时间的反馈回路。与时钟规程过程相关联的是时钟调整过程,该过程每秒运行一次,以注入计算出的时间偏移并保持恒定频率。过去时间偏移差的RMS平均值表示标称误差或系统时钟抖动。过去频率偏移差的RMS平均值表示振荡器频率稳定性或频率漂移。这些术语在第11.3节中给出了精确的解释。

A client sends messages to each server with a poll interval of 2^tau seconds, as determined by the poll exponent tau. In NTPv4, tau ranges from 4 (16 s) to 17 (36 h). The value of tau is determined by the clock discipline algorithm to match the loop-time constant T_c = 2^tau. In client/server mode, the server responds immediately; however, in symmetric modes, each of two peers manages tau as a function of current system offset and system jitter, so they may not agree with the same value. It is important that the dynamic behavior of the clock discipline algorithm be carefully controlled in order to maintain stability in the NTP subnet at large. This requires that

客户端以2^tau秒的轮询间隔向每个服务器发送消息,轮询间隔由轮询指数tau确定。在NTPv4中,tau的范围为4(16秒)到17(36小时)。tau的值由时钟规程算法确定,以匹配循环时间常数T_c=2^tau。在客户机/服务器模式下,服务器立即响应;然而,在对称模式下,两个对等点中的每一个管理tau作为当前系统偏移和系统抖动的函数,因此它们可能不符合相同的值。重要的是,仔细控制时钟规程算法的动态行为,以便在整个NTP子网中保持稳定性。这就要求

the peers agree on a common tau equal to the minimum poll exponent of both peers. The NTP protocol includes provisions to properly negotiate this value.

对等点同意一个公共tau,该tau等于两个对等点的最小投票指数。NTP协议包括适当协商该值的条款。

The implementation model includes some means to set and adjust the system clock. The operating system is assumed to provide two functions: one to set the time directly, for example, the Unix settimeofday() function, and another to adjust the time in small increments advancing or retarding the time by a designated amount, for example, the Unix adjtime() function. In this and following references, parentheses following a name indicate reference to a function rather than a simple variable. In the intended design the clock discipline process uses the adjtime() function if the adjustment is less than a designated threshold, and the settimeofday() function if above the threshold. The manner in which this is done and the value of the threshold as described in Section 10.

实现模型包括一些设置和调整系统时钟的方法。假定操作系统提供两个函数:一个用于直接设置时间,例如Unix settimeofday()函数;另一个用于以小增量调整时间,将时间提前或延迟指定的量,例如Unix adjtime()函数。在本引用和后面的引用中,名称后面的括号表示对函数的引用,而不是对简单变量的引用。在预期的设计中,如果调整小于指定的阈值,时钟规程过程使用adjtime()函数,如果高于阈值,则使用settimeofday()函数。完成此操作的方式以及第10节中描述的阈值。

6. Data Types
6. 数据类型

All NTP time values are represented in twos-complement format, with bits numbered in big-endian (as described in Appendix A of [RFC0791]) fashion from zero starting at the left, or high-order, position. There are three NTP time formats, a 128-bit date format, a 64-bit timestamp format, and a 32-bit short format, as shown in Figure 3. The 128-bit date format is used where sufficient storage and word size are available. It includes a 64-bit signed seconds field spanning 584 billion years and a 64-bit fraction field resolving .05 attosecond (i.e., 0.5e-18). For convenience in mapping between formats, the seconds field is divided into a 32-bit Era Number field and a 32-bit Era Offset field. Eras cannot be produced by NTP directly, nor is there need to do so. When necessary, they can be derived from external means, such as the filesystem or dedicated hardware.

所有NTP时间值均以twos补码格式表示,位以大端(如[RFC0791]附录A所述)方式从零开始编号,从左或高阶位置开始。有三种NTP时间格式:128位日期格式、64位时间戳格式和32位短格式,如图3所示。如果有足够的存储空间和字长,则使用128位日期格式。它包括一个跨越5840亿年的64位有符号秒字段和一个分辨率为.05阿秒(即0.5e-18)的64位分数字段。为了便于格式之间的映射,秒字段分为32位纪元编号字段和32位纪元偏移字段。NTP不能直接生成电子逆向拍卖,也没有必要这样做。必要时,它们可以从外部手段派生,如文件系统或专用硬件。

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Seconds              |           Fraction            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Seconds              |           Fraction            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

NTP Short Format

NTP短格式

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                            Seconds                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                            Fraction                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                            Seconds                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                            Fraction                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

NTP Timestamp Format

NTP时间戳格式

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Era Number                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Era Offset                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                           Fraction                            |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Era Number                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           Era Offset                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                           Fraction                            |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

NTP Date Format

NTP日期格式

Figure 3: NTP Time Formats

图3:NTP时间格式

The 64-bit timestamp format is used in packet headers and other places with limited word size. It includes a 32-bit unsigned seconds field spanning 136 years and a 32-bit fraction field resolving 232 picoseconds. The 32-bit short format is used in delay and dispersion header fields where the full resolution and range of the other formats are not justified. It includes a 16-bit unsigned seconds field and a 16-bit fraction field.

64位时间戳格式用于数据包头和其他字大小有限的地方。它包括一个跨度为136年的32位无符号秒字段和一个分辨率为232皮秒的32位分数字段。32位短格式用于延迟和色散标头字段,其中其他格式的完整分辨率和范围不合理。它包括一个16位无符号秒字段和一个16位分数字段。

In the date and timestamp formats, the prime epoch, or base date of era 0, is 0 h 1 January 1900 UTC, when all bits are zero. It should be noted that strictly speaking, UTC did not exist prior to 1 January 1972, but it is convenient to assume it has existed for all eternity, even if all knowledge of historic leap seconds has been lost. Dates are relative to the prime epoch; values greater than zero represent

在日期和时间戳格式中,原始历元或纪元0的基准日期为0小时1900年1月1日UTC,此时所有位均为零。应该注意的是,严格地说,UTC在1972年1月1日之前并不存在,但可以假设它一直存在,即使历史闰秒的所有知识都已丢失。日期与黄金时代有关;大于零的值表示

times after that date; values less than zero represent times before it. Note that the Era Offset field of the date format and the Seconds field of the timestamp format have the same interpretation.

该日期之后的时间;小于零的值表示之前的时间。请注意,日期格式的纪元偏移字段和时间戳格式的秒字段具有相同的解释。

Timestamps are unsigned values, and operations on them produce a result in the same or adjacent eras. Era 0 includes dates from the prime epoch to some time in 2036, when the timestamp field wraps around and the base date for era 1 is established. In either format, a value of zero is a special case representing unknown or unsynchronized time. Figure 4 shows a number of historic NTP dates together with their corresponding Modified Julian Day (MJD), NTP era, and NTP timestamp.

时间戳是无符号值,对它们的操作会在相同或相邻的纪元中产生结果。纪元0包括从主纪元到2036年某个时间的日期,此时时间戳字段结束,纪元1的基准日期已确定。在任何一种格式中,零值都是表示未知或不同步时间的特例。图4显示了许多历史NTP日期及其相应的修改朱利安日(MJD)、NTP纪元和NTP时间戳。

   +-------------+------------+-----+---------------+------------------+
   | Date        | MJD        | NTP | NTP Timestamp | Epoch            |
   |             |            | Era | Era Offset    |                  |
   +-------------+------------+-----+---------------+------------------+
   | 1 Jan -4712 | -2,400,001 | -49 | 1,795,583,104 | 1st day Julian   |
   | 1 Jan -1    | -679,306   | -14 | 139,775,744   | 2 BCE            |
   | 1 Jan 0     | -678,491   | -14 | 171,311,744   | 1 BCE            |
   | 1 Jan 1     | -678,575   | -14 | 202,939,144   | 1 CE             |
   | 4 Oct 1582  | -100,851   | -3  | 2,873,647,488 | Last day Julian  |
   | 15 Oct 1582 | -100,840   | -3  | 2,874,597,888 | First day        |
   |             |            |     |               | Gregorian        |
   | 31 Dec 1899 | 15019      | -1  | 4,294,880,896 | Last day NTP Era |
   |             |            |     |               | -1               |
   | 1 Jan 1900  | 15020      | 0   | 0             | First day NTP    |
   |             |            |     |               | Era 0            |
   | 1 Jan 1970  | 40,587     | 0   | 2,208,988,800 | First day UNIX   |
   | 1 Jan 1972  | 41,317     | 0   | 2,272,060,800 | First day UTC    |
   | 31 Dec 1999 | 51,543     | 0   | 3,155,587,200 | Last day 20th    |
   |             |            |     |               | Century          |
   | 8 Feb 2036  | 64,731     | 1   | 63,104        | First day NTP    |
   |             |            |     |               | Era 1            |
   +-------------+------------+-----+---------------+------------------+
        
   +-------------+------------+-----+---------------+------------------+
   | Date        | MJD        | NTP | NTP Timestamp | Epoch            |
   |             |            | Era | Era Offset    |                  |
   +-------------+------------+-----+---------------+------------------+
   | 1 Jan -4712 | -2,400,001 | -49 | 1,795,583,104 | 1st day Julian   |
   | 1 Jan -1    | -679,306   | -14 | 139,775,744   | 2 BCE            |
   | 1 Jan 0     | -678,491   | -14 | 171,311,744   | 1 BCE            |
   | 1 Jan 1     | -678,575   | -14 | 202,939,144   | 1 CE             |
   | 4 Oct 1582  | -100,851   | -3  | 2,873,647,488 | Last day Julian  |
   | 15 Oct 1582 | -100,840   | -3  | 2,874,597,888 | First day        |
   |             |            |     |               | Gregorian        |
   | 31 Dec 1899 | 15019      | -1  | 4,294,880,896 | Last day NTP Era |
   |             |            |     |               | -1               |
   | 1 Jan 1900  | 15020      | 0   | 0             | First day NTP    |
   |             |            |     |               | Era 0            |
   | 1 Jan 1970  | 40,587     | 0   | 2,208,988,800 | First day UNIX   |
   | 1 Jan 1972  | 41,317     | 0   | 2,272,060,800 | First day UTC    |
   | 31 Dec 1999 | 51,543     | 0   | 3,155,587,200 | Last day 20th    |
   |             |            |     |               | Century          |
   | 8 Feb 2036  | 64,731     | 1   | 63,104        | First day NTP    |
   |             |            |     |               | Era 1            |
   +-------------+------------+-----+---------------+------------------+
        

Figure 4: Interesting Historic NTP Dates

图4:有趣的历史NTP日期

Let p be the number of significant bits in the second fraction. The clock resolution is defined as 2^(-p), in seconds. In order to minimize bias and help make timestamps unpredictable to an intruder, the non-significant bits should be set to an unbiased random bit string. The clock precision is defined as the running time to read the system clock, in seconds. Note that the precision defined in this way can be larger or smaller than the resolution. The term rho, representing the precision used in the protocol, is the larger of the two.

设p为第二个分数中的有效位数。时钟分辨率定义为2^(-p),以秒为单位。为了最小化偏差并帮助入侵者预测时间戳,非有效位应设置为无偏差随机位字符串。时钟精度定义为读取系统时钟的运行时间,以秒为单位。请注意,以这种方式定义的精度可以大于或小于分辨率。表示协议中使用的精度的术语rho是两者中较大的一个。

The only arithmetic operation permitted on dates and timestamps is twos-complement subtraction, yielding a 127-bit or 63-bit signed result. It is critical that the first-order differences between two dates preserve the full 128-bit precision and the first-order differences between two timestamps preserve the full 64-bit precision. However, the differences are ordinarily small compared to the seconds span, so they can be converted to floating double format for further processing and without compromising the precision.

日期和时间戳上唯一允许的算术运算是两个补码减法,产生127位或63位有符号结果。至关重要的是,两个日期之间的一阶差保持完整的128位精度,两个时间戳之间的一阶差保持完整的64位精度。但是,与秒跨度相比,差异通常很小,因此可以将其转换为浮动双精度格式进行进一步处理,而不会影响精度。

It is important to note that twos-complement arithmetic does not distinguish between signed and unsigned values (although comparisons can take sign into account); only the conditional branch instructions do. Thus, although the distinction is made between signed dates and unsigned timestamps, they are processed the same way. A perceived hazard with 64-bit timestamp calculations spanning an era, such as is possible in 2036, might result in over-run. In point of fact, if the client is set within 68 years of the server before the protocol is started, correct values are obtained even if the client and server are in adjacent eras.

需要注意的是,twos补码算法不区分有符号值和无符号值(尽管比较可以考虑符号);只有条件分支指令才能执行此操作。因此,尽管有符号日期和无符号时间戳之间有区别,但它们的处理方式是相同的。使用跨越一个纪元的64位时间戳计算(如2036年可能出现的)感知到的危险可能会导致过度运行。事实上,如果在协议启动之前将客户机设置在服务器的68年内,则即使客户机和服务器处于相邻的纪元中,也会获得正确的值。

Some time values are represented in exponent format, including the precision, time constant, and poll interval. These are in 8-bit signed integer format in log2 (log base 2) seconds. The only arithmetic operations permitted on them are increment and decrement. For the purpose of this document and to simplify the presentation, a reference to one of these variables by name means the exponentiated value, e.g., the poll interval is 1024 s, while reference by name and exponent means the actual value, e.g., the poll exponent is 10.

某些时间值以指数格式表示,包括精度、时间常数和轮询间隔。它们是以log2(logbase 2)秒为单位的8位有符号整数格式。它们唯一允许的算术运算是递增和递减。为了本文件的目的和简化演示,按名称引用其中一个变量表示指数值,例如轮询间隔为1024 s,而按名称和指数引用表示实际值,例如轮询指数为10。

To convert system time in any format to NTP date and timestamp formats requires that the number of seconds s from the prime epoch to the system time be determined. To determine the integer era and timestamp given s,

要将任何格式的系统时间转换为NTP日期和时间戳格式,需要确定从原始历元到系统时间的秒数。要确定给定时间戳的整数纪元和时间戳,

era = s / 2^(32) and timestamp = s - era * 2^(32),

era=s/2^(32)和timestamp=s-era*2^(32),

which works for positive and negative dates. To determine s given the era and timestamp,

适用于正反日期。要确定给定纪元和时间戳的时间,

s = era * 2^(32) + timestamp.

s=纪元*2^(32)+时间戳。

Converting between NTP and system time can be a little messy, and is beyond the scope of this document. Note that the number of days in era 0 is one more than the number of days in most other eras, and this won't happen again until the year 2400 in era 3.

NTP和系统时间之间的转换可能有点混乱,超出了本文档的范围。请注意,纪元0中的天数比大多数其他纪元中的天数多一天,并且在纪元3中的2400年之前不会再次发生这种情况。

In the description of state variables to follow, explicit reference to integer type implies a 32-bit unsigned integer. This simplifies bounds checks, since only the upper limit needs to be defined. Without explicit reference, the default type is 64-bit floating double. Exceptions will be noted as necessary.

在接下来的状态变量描述中,对integer类型的显式引用意味着一个32位无符号整数。这简化了边界检查,因为只需要定义上限。如果没有显式引用,默认类型为64位浮点双精度。必要时将注明例外情况。

7. Data Structures
7. 数据结构

The NTP state machines are defined in the following sections. State variables are separated into classes according to their function in packet headers, peer and poll processes, the system process, and the clock discipline process. Packet variables represent the NTP header values in transmitted and received packets. Peer and poll variables represent the contents of the association for each server separately. System variables represent the state of the server as seen by its dependent clients. Clock discipline variables represent the internal workings of the clock discipline algorithm. An example is described in Appendix A.

NTP状态机在以下部分中定义。状态变量根据其在数据包头、对等进程和轮询进程、系统进程和时钟规程进程中的功能划分为类。数据包变量表示传输和接收数据包中的NTP报头值。对等变量和轮询变量分别表示每个服务器的关联内容。系统变量表示服务器的从属客户端所看到的服务器状态。时钟规程变量表示时钟规程算法的内部工作。附录A中描述了一个示例。

7.1. Structure Conventions
7.1. 结构约定

In order to distinguish between different variables of the same name but used in different processes, the naming convention summarized in Figure 5 is adopted. A receive packet variable v is a member of the packet structure r with fully qualified name r.v. In a similar manner, x.v is a transmit packet variable, p.v is a peer variable, s.v is a system variable, and c.v is a clock discipline variable. There is a set of peer variables for each association; there is only one set of system and clock variables.

为了区分相同名称但在不同过程中使用的不同变量,采用了图5中总结的命名约定。接收分组变量v是具有完全限定名称r.v的分组结构r的成员。以类似方式,x.v是发送分组变量,p.v是对等变量,s.v是系统变量,c.v是时钟规程变量。每个关联都有一组对等变量;只有一组系统和时钟变量。

                   +------+---------------------------------+
                   | Name | Description                     |
                   +------+---------------------------------+
                   | r.   | receive packet header variable  |
                   | x.   | transmit packet header variable |
                   | p.   | peer/poll variable              |
                   | s.   | system variable                 |
                   | c.   | clock discipline variable       |
                   +------+---------------------------------+
        
                   +------+---------------------------------+
                   | Name | Description                     |
                   +------+---------------------------------+
                   | r.   | receive packet header variable  |
                   | x.   | transmit packet header variable |
                   | p.   | peer/poll variable              |
                   | s.   | system variable                 |
                   | c.   | clock discipline variable       |
                   +------+---------------------------------+
        

Figure 5: Prefix Conventions

图5:前缀约定

7.2. Global Parameters
7.2. 全局参数

In addition to the variable classes, a number of global parameters are defined in this document, including those shown with values in Figure 6.

除了变量类之外,本文还定义了一些全局参数,包括图6中显示的值。

            +-----------+-------+----------------------------------+
            | Name      | Value | Description                      |
            +-----------+-------+----------------------------------+
            | PORT      | 123   | NTP port number                  |
            | VERSION   | 4     | NTP version number                   |
            | TOLERANCE | 15e-6 | frequency tolerance PHI (s/s)    |
            | MINPOLL   | 4     | minimum poll exponent (16 s)     |
            | MAXPOLL   | 17    | maximum poll exponent (36 h)     |
            | MAXDISP   | 16    | maximum dispersion (16 s)        |
            | MINDISP   | .005  | minimum dispersion increment (s) |
            | MAXDIST   | 1     | distance threshold (1 s)         |
            | MAXSTRAT  | 16    | maximum stratum number           |
            +-----------+-------+----------------------------------+
        
            +-----------+-------+----------------------------------+
            | Name      | Value | Description                      |
            +-----------+-------+----------------------------------+
            | PORT      | 123   | NTP port number                  |
            | VERSION   | 4     | NTP version number                   |
            | TOLERANCE | 15e-6 | frequency tolerance PHI (s/s)    |
            | MINPOLL   | 4     | minimum poll exponent (16 s)     |
            | MAXPOLL   | 17    | maximum poll exponent (36 h)     |
            | MAXDISP   | 16    | maximum dispersion (16 s)        |
            | MINDISP   | .005  | minimum dispersion increment (s) |
            | MAXDIST   | 1     | distance threshold (1 s)         |
            | MAXSTRAT  | 16    | maximum stratum number           |
            +-----------+-------+----------------------------------+
        

Figure 6: Global Parameters

图6:全局参数

While these are the only global parameters needed for interoperability, a larger collection is necessary in any implementation. Appendix A.1.1 contains those used by the skeleton for the mitigation algorithms, clock discipline algorithm, and related implementation-dependent functions. Some of these parameter values are cast in stone, like the NTP port number assigned by the IANA and the version number assigned NTPv4 itself. Others, like the frequency tolerance (also called PHI), involve an assumption about the worst-case behavior of a system clock once synchronized and then allowed to drift when its sources have become unreachable. The minimum and maximum parameters define the limits of state variables as described in later sections of this document.

虽然这些是互操作性所需的唯一全局参数,但在任何实现中都需要更大的集合。附录A.1.1包含了框架使用的缓解算法、时钟规程算法和相关的实现相关功能。其中一些参数值是一成不变的,比如IANA分配的NTP端口号和NTPv4本身分配的版本号。另一些,如频率容差(也称为PHI),涉及到系统时钟一旦同步,然后在无法到达其源时允许漂移的最坏情况行为的假设。最小和最大参数定义了状态变量的限制,如本文件后面章节所述。

While shown with fixed values in this document, some implementations may make them variables adjustable by configuration commands. For instance, the reference implementation computes the value of PRECISION as log2 of the minimum time in several iterations to read the system clock.

虽然在本文档中以固定值显示,但一些实现可能会使它们通过配置命令进行调整。例如,参考实现将精度值计算为几个迭代中读取系统时钟的最短时间的log2。

7.3. Packet Header Variables
7.3. 包头变量

The most important state variables from an external point of view are the packet header variables described in Figure 7 and below. The NTP packet header consists of an integral number of 32-bit (4 octet) words in network byte order. The packet format consists of three components: the header itself, one or more optional extension fields, and an optional message authentication code (MAC). The header component is identical to the NTPv3 header and previous versions. The optional extension fields are used by the Autokey public key cryptographic algorithms described in [RFC5906]. The optional MAC is used by both Autokey and the symmetric key cryptographic algorithm described in this RFC.

从外部角度来看,最重要的状态变量是图7和下面描述的数据包头变量。NTP数据包头由整数个32位(4个八位字节)字组成,按网络字节顺序排列。数据包格式由三个组件组成:报头本身、一个或多个可选扩展字段和可选消息身份验证码(MAC)。标头组件与NTPv3标头和早期版本相同。可选扩展字段由[RFC5906]中描述的自动密钥公钥加密算法使用。可选MAC由本RFC中描述的自动密钥和对称密钥加密算法使用。

               +-----------+------------+-----------------------+
               | Name      | Formula    | Description           |
               +-----------+------------+-----------------------+
               | leap      | leap       | leap indicator (LI)   |
               | version   | version    | version number (VN)   |
               | mode      | mode       | mode                  |
               | stratum   | stratum    | stratum               |
               | poll      | poll       | poll exponent         |
               | precision | rho        | precision exponent    |
               | rootdelay | delta_r    | root delay            |
               | rootdisp  | epsilon_r  | root dispersion       |
               | refid     | refid      | reference ID          |
               | reftime   | reftime    | reference timestamp   |
               | org       | T1         | origin timestamp      |
               | rec       | T2         | receive timestamp     |
               | xmt       | T3         | transmit timestamp    |
               | dst       | T4         | destination timestamp |
               | keyid     | keyid      | key ID                |
               | dgst      | dgst       | message digest        |
               +-----------+------------+-----------------------+
        
               +-----------+------------+-----------------------+
               | Name      | Formula    | Description           |
               +-----------+------------+-----------------------+
               | leap      | leap       | leap indicator (LI)   |
               | version   | version    | version number (VN)   |
               | mode      | mode       | mode                  |
               | stratum   | stratum    | stratum               |
               | poll      | poll       | poll exponent         |
               | precision | rho        | precision exponent    |
               | rootdelay | delta_r    | root delay            |
               | rootdisp  | epsilon_r  | root dispersion       |
               | refid     | refid      | reference ID          |
               | reftime   | reftime    | reference timestamp   |
               | org       | T1         | origin timestamp      |
               | rec       | T2         | receive timestamp     |
               | xmt       | T3         | transmit timestamp    |
               | dst       | T4         | destination timestamp |
               | keyid     | keyid      | key ID                |
               | dgst      | dgst       | message digest        |
               +-----------+------------+-----------------------+
        

Figure 7: Packet Header Variables

图7:数据包头变量

The NTP packet is a UDP datagram [RFC0768]. Some fields use multiple words and others are packed in smaller fields within a word. The NTP packet header shown in Figure 8 has 12 words followed by optional extension fields and finally an optional message authentication code (MAC) consisting of the Key Identifier field and Message Digest field.

NTP数据包是UDP数据报[RFC0768]。有些字段使用多个单词,而另一些字段则压缩在一个单词中较小的字段中。图8所示的NTP数据包头有12个字,后面是可选的扩展字段,最后是可选的消息认证码(MAC),由密钥标识符字段和消息摘要字段组成。

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |LI | VN  |Mode |    Stratum     |     Poll      |  Precision   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Root Delay                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Root Dispersion                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          Reference ID                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                     Reference Timestamp (64)                  +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Origin Timestamp (64)                    +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Receive Timestamp (64)                   +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Transmit Timestamp (64)                  +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      .                                                               .
      .                    Extension Field 1 (variable)               .
      .                                                               .
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      .                                                               .
      .                    Extension Field 2 (variable)               .
      .                                                               .
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          Key Identifier                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                            dgst (128)                         |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |LI | VN  |Mode |    Stratum     |     Poll      |  Precision   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Root Delay                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Root Dispersion                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          Reference ID                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                     Reference Timestamp (64)                  +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Origin Timestamp (64)                    +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Receive Timestamp (64)                   +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                      Transmit Timestamp (64)                  +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      .                                                               .
      .                    Extension Field 1 (variable)               .
      .                                                               .
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      .                                                               .
      .                    Extension Field 2 (variable)               .
      .                                                               .
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          Key Identifier                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                            dgst (128)                         |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

Figure 8: Packet Header Format

图8:数据包头格式

The extension fields are used to add optional capabilities, for example, the Autokey security protocol [RFC5906]. The extension field format is presented in order for the packet to be parsed without the knowledge of the extension field functions. The MAC is used by both Autokey and the symmetric key authentication scheme.

扩展字段用于添加可选功能,例如,自动密钥安全协议[RFC5906]。提供扩展字段格式是为了在不了解扩展字段函数的情况下解析数据包。MAC由自动密钥和对称密钥认证方案使用。

A list of the packet header variables is shown in Figure 7 and described in detail below. Except for a minor variation when using the IPv6 address family, these fields are backwards compatible with NTPv3. The packet header fields apply to both transmitted packets (x prefix) and received packets (r prefix). In Figure 8, the size of some multiple-word fields is shown in bits if not the default 32 bits. The basic header extends from the beginning of the packet to the end of the Transmit Timestamp field.

包头变量列表如图7所示,并在下面详细描述。除了使用IPv6地址系列时的一个微小变化外,这些字段与NTPv3向后兼容。数据包头字段适用于传输数据包(x前缀)和接收数据包(r前缀)。在图8中,如果不是默认的32位,则一些多字字段的大小以位表示。基本报头从数据包的开始延伸到传输时间戳字段的结束。

The fields and associated packet variables (in parentheses) are interpreted as follows:

字段和相关数据包变量(括号中)解释如下:

LI Leap Indicator (leap): 2-bit integer warning of an impending leap second to be inserted or deleted in the last minute of the current month with values defined in Figure 9.

LI Leap指示器(Leap):在当前月份的最后一分钟插入或删除即将到来的闰秒的2位整数警告,其值如图9所示。

           +-------+----------------------------------------+
           | Value | Meaning                                |
           +-------+----------------------------------------+
           | 0     | no warning                             |
           | 1     | last minute of the day has 61 seconds  |
           | 2     | last minute of the day has 59 seconds  |
           | 3     | unknown (clock unsynchronized)         |
           +-------+----------------------------------------+
        
           +-------+----------------------------------------+
           | Value | Meaning                                |
           +-------+----------------------------------------+
           | 0     | no warning                             |
           | 1     | last minute of the day has 61 seconds  |
           | 2     | last minute of the day has 59 seconds  |
           | 3     | unknown (clock unsynchronized)         |
           +-------+----------------------------------------+
        

Figure 9: Leap Indicator

图9:跳跃指示器

VN Version Number (version): 3-bit integer representing the NTP version number, currently 4.

VN版本号(Version):表示NTP版本号的3位整数,当前为4。

Mode (mode): 3-bit integer representing the mode, with values defined in Figure 10.

Mode(Mode):表示模式的3位整数,值如图10所示。

                      +-------+--------------------------+
                      | Value | Meaning                  |
                      +-------+--------------------------+
                      | 0     | reserved                 |
                      | 1     | symmetric active         |
                      | 2     | symmetric passive        |
                      | 3     | client                   |
                      | 4     | server                   |
                      | 5     | broadcast                |
                      | 6     | NTP control message      |
                      | 7     | reserved for private use |
                      +-------+--------------------------+
        
                      +-------+--------------------------+
                      | Value | Meaning                  |
                      +-------+--------------------------+
                      | 0     | reserved                 |
                      | 1     | symmetric active         |
                      | 2     | symmetric passive        |
                      | 3     | client                   |
                      | 4     | server                   |
                      | 5     | broadcast                |
                      | 6     | NTP control message      |
                      | 7     | reserved for private use |
                      +-------+--------------------------+
        

Figure 10: Association Modes

图10:关联模式

Stratum (stratum): 8-bit integer representing the stratum, with values defined in Figure 11.

地层(Stratum):表示地层的8位整数,其值如图11所示。

        +--------+-----------------------------------------------------+
        | Value  | Meaning                                             |
        +--------+-----------------------------------------------------+
        | 0      | unspecified or invalid                              |
        | 1      | primary server (e.g., equipped with a GPS receiver) |
        | 2-15   | secondary server (via NTP)                          |
        | 16     | unsynchronized                                      |
        | 17-255 | reserved                                            |
        +--------+-----------------------------------------------------+
        
        +--------+-----------------------------------------------------+
        | Value  | Meaning                                             |
        +--------+-----------------------------------------------------+
        | 0      | unspecified or invalid                              |
        | 1      | primary server (e.g., equipped with a GPS receiver) |
        | 2-15   | secondary server (via NTP)                          |
        | 16     | unsynchronized                                      |
        | 17-255 | reserved                                            |
        +--------+-----------------------------------------------------+
        

Figure 11: Packet Stratum

图11:数据包层

It is customary to map the stratum value 0 in received packets to MAXSTRAT (16) in the peer variable p.stratum and to map p.stratum values of MAXSTRAT or greater to 0 in transmitted packets. This allows reference clocks, which normally appear at stratum 0, to be conveniently mitigated using the same clock selection algorithms used for external sources (see Appendix A.5.5.1 for an example).

通常,将接收数据包中的层值0映射到对等变量p.strata中的MAXSTRAT(16),并将发送数据包中的MAXSTRAT或更大的p.strata值映射到0。这允许使用用于外部源的相同时钟选择算法(示例见附录A.5.5.1)方便地缓解通常出现在第0层的参考时钟。

Poll: 8-bit signed integer representing the maximum interval between successive messages, in log2 seconds. Suggested default limits for minimum and maximum poll intervals are 6 and 10, respectively.

轮询:8位有符号整数,表示连续消息之间的最大间隔,以log2秒为单位。建议的最小和最大轮询间隔的默认限制分别为6和10。

Precision: 8-bit signed integer representing the precision of the system clock, in log2 seconds. For instance, a value of -18 corresponds to a precision of about one microsecond. The precision can be determined when the service first starts up as the minimum time of several iterations to read the system clock.

精度:表示系统时钟精度的8位有符号整数,以log2秒为单位。例如,-18对应于大约一微秒的精度。精度可以在服务首次启动时确定,作为读取系统时钟的几次迭代的最短时间。

Root Delay (rootdelay): Total round-trip delay to the reference clock, in NTP short format.

根延迟(rootdelay):参考时钟的总往返延迟,采用NTP短格式。

Root Dispersion (rootdisp): Total dispersion to the reference clock, in NTP short format.

根色散(rootdisp):参考时钟的总色散,NTP短格式。

Reference ID (refid): 32-bit code identifying the particular server or reference clock. The interpretation depends on the value in the stratum field. For packet stratum 0 (unspecified or invalid), this is a four-character ASCII [RFC1345] string, called the "kiss code", used for debugging and monitoring purposes. For stratum 1 (reference clock), this is a four-octet, left-justified, zero-padded ASCII string assigned to the reference clock. The authoritative list of Reference Identifiers is maintained by IANA; however, any string beginning with the ASCII character "X" is reserved for unregistered experimentation and development. The identifiers in Figure 12 have been used as ASCII identifiers:

参考ID(refid):标识特定服务器或参考时钟的32位代码。解释取决于地层字段中的值。对于数据包层0(未指定或无效),这是一个四字符ASCII[RFC1345]字符串,称为“kiss代码”,用于调试和监视目的。对于第1层(参考时钟),这是分配给参考时钟的四个八位字节、左对齐、零填充ASCII字符串。IANA维护参考标识符的权威列表;但是,任何以ASCII字符“X”开头的字符串都保留用于未注册的实验和开发。图12中的标识符被用作ASCII标识符:

     +------+----------------------------------------------------------+
     | ID   | Clock Source                                             |
     +------+----------------------------------------------------------+
     | GOES | Geosynchronous Orbit Environment Satellite               |
     | GPS  | Global Position System                                   |
     | GAL  | Galileo Positioning System                               |
     | PPS  | Generic pulse-per-second                                 |
     | IRIG | Inter-Range Instrumentation Group                        |
     | WWVB | LF Radio WWVB Ft. Collins, CO 60 kHz                     |
     | DCF  | LF Radio DCF77 Mainflingen, DE 77.5 kHz                  |
     | HBG  | LF Radio HBG Prangins, HB 75 kHz                         |
     | MSF  | LF Radio MSF Anthorn, UK 60 kHz                          |
     | JJY  | LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz       |
     | LORC | MF Radio LORAN C station, 100 kHz                        |
     | TDF  | MF Radio Allouis, FR 162 kHz                             |
     | CHU  | HF Radio CHU Ottawa, Ontario                             |
     | WWV  | HF Radio WWV Ft. Collins, CO                             |
     | WWVH | HF Radio WWVH Kauai, HI                                  |
     | NIST | NIST telephone modem                                     |
     | ACTS | NIST telephone modem                                     |
     | USNO | USNO telephone modem                                     |
     | PTB  | European telephone modem                                 |
     +------+----------------------------------------------------------+
        
     +------+----------------------------------------------------------+
     | ID   | Clock Source                                             |
     +------+----------------------------------------------------------+
     | GOES | Geosynchronous Orbit Environment Satellite               |
     | GPS  | Global Position System                                   |
     | GAL  | Galileo Positioning System                               |
     | PPS  | Generic pulse-per-second                                 |
     | IRIG | Inter-Range Instrumentation Group                        |
     | WWVB | LF Radio WWVB Ft. Collins, CO 60 kHz                     |
     | DCF  | LF Radio DCF77 Mainflingen, DE 77.5 kHz                  |
     | HBG  | LF Radio HBG Prangins, HB 75 kHz                         |
     | MSF  | LF Radio MSF Anthorn, UK 60 kHz                          |
     | JJY  | LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz       |
     | LORC | MF Radio LORAN C station, 100 kHz                        |
     | TDF  | MF Radio Allouis, FR 162 kHz                             |
     | CHU  | HF Radio CHU Ottawa, Ontario                             |
     | WWV  | HF Radio WWV Ft. Collins, CO                             |
     | WWVH | HF Radio WWVH Kauai, HI                                  |
     | NIST | NIST telephone modem                                     |
     | ACTS | NIST telephone modem                                     |
     | USNO | USNO telephone modem                                     |
     | PTB  | European telephone modem                                 |
     +------+----------------------------------------------------------+
        

Figure 12: Reference Identifiers

图12:参考标识符

Above stratum 1 (secondary servers and clients): this is the reference identifier of the server and can be used to detect timing loops. If using the IPv4 address family, the identifier is the four-octet IPv4 address. If using the IPv6 address family, it is the

第1层以上(辅助服务器和客户端):这是服务器的参考标识符,可用于检测定时循环。如果使用IPv4地址系列,则标识符为四个八位字节的IPv4地址。如果使用IPv6地址系列,则为

first four octets of the MD5 hash of the IPv6 address. Note that, when using the IPv6 address family on an NTPv4 server with a NTPv3 client, the Reference Identifier field appears to be a random value and a timing loop might not be detected.

IPv6地址MD5哈希的前四个八位字节。请注意,在带有NTPv3客户端的NTPv4服务器上使用IPv6地址系列时,参考标识符字段似乎是一个随机值,可能无法检测到定时循环。

Reference Timestamp: Time when the system clock was last set or corrected, in NTP timestamp format.

参考时间戳:以NTP时间戳格式最后设置或更正系统时钟的时间。

Origin Timestamp (org): Time at the client when the request departed for the server, in NTP timestamp format.

Origin Timestamp(org):请求离开服务器时客户端的时间,采用NTP时间戳格式。

Receive Timestamp (rec): Time at the server when the request arrived from the client, in NTP timestamp format.

接收时间戳(rec):以NTP时间戳格式从客户端到达服务器的时间。

Transmit Timestamp (xmt): Time at the server when the response left for the client, in NTP timestamp format.

Transmit Timestamp(xmt):响应留给客户端时服务器上的时间,采用NTP时间戳格式。

Destination Timestamp (dst): Time at the client when the reply arrived from the server, in NTP timestamp format.

目的地时间戳(dst):从服务器收到回复时客户端的时间,采用NTP时间戳格式。

Note: The Destination Timestamp field is not included as a header field; it is determined upon arrival of the packet and made available in the packet buffer data structure.

注意:目的地时间戳字段不包括在标题字段中;它在分组到达时确定,并在分组缓冲区数据结构中可用。

If the NTP has access to the physical layer, then the timestamps are associated with the beginning of the symbol after the start of frame. Otherwise, implementations should attempt to associate the timestamp to the earliest accessible point in the frame.

如果NTP可以访问物理层,则时间戳与帧开始后的符号开始相关联。否则,实现应该尝试将时间戳与帧中最早的可访问点相关联。

The MAC consists of the Key Identifier followed by the Message Digest. The message digest, or cryptosum, is calculated as in [RFC1321] over all NTP-header and optional extension fields, but not the MAC itself.

MAC由密钥标识符和消息摘要组成。按照[RFC1321]对所有NTP头和可选扩展字段(而不是MAC本身)计算消息摘要或加密总和。

Extension Field n: See Section 7.5 for a description of the format of this field.

扩展字段n:有关此字段格式的说明,请参见第7.5节。

Key Identifier (keyid): 32-bit unsigned integer used by the client and server to designate a secret 128-bit MD5 key.

密钥标识符(keyid):客户端和服务器用于指定128位MD5密钥的32位无符号整数。

Message Digest (digest): 128-bit MD5 hash computed over the key followed by the NTP packet header and extensions fields (but not the Key Identifier or Message Digest fields).

消息摘要(Digest):在密钥上计算128位MD5哈希,后跟NTP数据包头和扩展字段(但不是密钥标识符或消息摘要字段)。

It should be noted that the MAC computation used here differs from those defined in [RFC1305] and [RFC4330] but is consistent with how existing implementations generate a MAC.

应注意,此处使用的MAC计算不同于[RFC1305]和[RFC4330]中定义的MAC计算,但与现有实现生成MAC的方式一致。

7.4. The Kiss-o'-Death Packet
7.4. 死亡之吻

If the Stratum field is 0, which implies unspecified or invalid, the Reference Identifier field can be used to convey messages useful for status reporting and access control. These are called Kiss-o'-Death (KoD) packets and the ASCII messages they convey are called kiss codes. The KoD packets got their name because an early use was to tell clients to stop sending packets that violate server access controls. The kiss codes can provide useful information for an intelligent client, either NTPv4 or SNTPv4. Kiss codes are encoded in four-character ASCII strings that are left justified and zero filled. The strings are designed for character displays and log files. A list of the currently defined kiss codes is given in Figure 13. Recipients of kiss codes MUST inspect them and, in the following cases, take these actions:

如果地层字段为0(表示未指定或无效),则参考标识符字段可用于传递对状态报告和访问控制有用的消息。这些称为Kiss-o'-Death(KoD)数据包,它们传递的ASCII消息称为Kiss代码。KoD数据包之所以得名,是因为早期的用途是告诉客户端停止发送违反服务器访问控制的数据包。kiss代码可以为智能客户端(NTPv4或SNTPv4)提供有用的信息。Kiss代码以四个字符的ASCII字符串进行编码,这些字符串左对齐,零填充。字符串用于字符显示和日志文件。图13给出了当前定义的kiss代码列表。kiss代码的接收者必须对其进行检查,并在以下情况下采取以下措施:

a. For kiss codes DENY and RSTR, the client MUST demobilize any associations to that server and stop sending packets to that server;

a. 对于kiss代码DENY和RSTR,客户端必须解除与该服务器的任何关联,并停止向该服务器发送数据包;

b. For kiss code RATE, the client MUST immediately reduce its polling interval to that server and continue to reduce it each time it receives a RATE kiss code.

b. 对于kiss代码速率,客户机必须立即缩短到该服务器的轮询间隔,并在每次收到速率kiss代码时继续缩短轮询间隔。

c. Kiss codes beginning with the ASCII character "X" are for unregistered experimentation and development and MUST be ignored if not recognized.

c. 以ASCII字符“X”开头的Kiss代码用于未注册的实验和开发,如果无法识别,则必须忽略。

d. Other than the above conditions, KoD packets have no protocol significance and are discarded after inspection.

d. 除上述情况外,KoD数据包没有协议意义,检查后丢弃。

   +------+------------------------------------------------------------+
   | Code |                           Meaning                          |
   +------+------------------------------------------------------------+
   | ACST | The association belongs to a unicast server.               |
   | AUTH | Server authentication failed.                              |
   | AUTO | Autokey sequence failed.                                   |
   | BCST | The association belongs to a broadcast server.             |
   | CRYP | Cryptographic authentication or identification failed.     |
   | DENY | Access denied by remote server.                            |
   | DROP | Lost peer in symmetric mode.                               |
   | RSTR | Access denied due to local policy.                         |
   | INIT | The association has not yet synchronized for the first     |
   |      | time.                                                      |
   | MCST | The association belongs to a dynamically discovered server.|
   | NKEY | No key found. Either the key was never installed or is     |
   |      | not trusted.                                               |
   | RATE | Rate exceeded. The server has temporarily denied access    |
   |      | because the client exceeded the rate threshold.            |
   | RMOT | Alteration of association from a remote host running       |
   |      | ntpdc.                                                     |
   | STEP | A step change in system time has occurred, but the         |
   |      | association has not yet resynchronized.                    |
   +------+------------------------------------------------------------+
        
   +------+------------------------------------------------------------+
   | Code |                           Meaning                          |
   +------+------------------------------------------------------------+
   | ACST | The association belongs to a unicast server.               |
   | AUTH | Server authentication failed.                              |
   | AUTO | Autokey sequence failed.                                   |
   | BCST | The association belongs to a broadcast server.             |
   | CRYP | Cryptographic authentication or identification failed.     |
   | DENY | Access denied by remote server.                            |
   | DROP | Lost peer in symmetric mode.                               |
   | RSTR | Access denied due to local policy.                         |
   | INIT | The association has not yet synchronized for the first     |
   |      | time.                                                      |
   | MCST | The association belongs to a dynamically discovered server.|
   | NKEY | No key found. Either the key was never installed or is     |
   |      | not trusted.                                               |
   | RATE | Rate exceeded. The server has temporarily denied access    |
   |      | because the client exceeded the rate threshold.            |
   | RMOT | Alteration of association from a remote host running       |
   |      | ntpdc.                                                     |
   | STEP | A step change in system time has occurred, but the         |
   |      | association has not yet resynchronized.                    |
   +------+------------------------------------------------------------+
        

Figure 13: Kiss Codes

图13:Kiss代码

The Receive Timestamp and the Transmit Timestamp (set by the server) are undefined when in a KoD packet and MUST NOT be relied upon to have valid values and MUST be discarded.

在KoD数据包中,接收时间戳和发送时间戳(由服务器设置)是未定义的,不能依赖于它们具有有效值,必须丢弃。

7.5. NTP Extension Field Format
7.5. NTP扩展字段格式

In NTPv4, one or more extension fields can be inserted after the header and before the MAC, which is always present when an extension field is present. Other than defining the field format, this document makes no use of the field contents. An extension field contains a request or response message in the format shown in Figure 14.

在NTPv4中,一个或多个扩展字段可以插入到报头之后和MAC之前,当存在扩展字段时,MAC始终存在。除定义字段格式外,本文档不使用字段内容。扩展字段包含如图14所示格式的请求或响应消息。

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Field Type           |            Length             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                            Value                              .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                       Padding (as needed)                     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Field Type           |            Length             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                            Value                              .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                       Padding (as needed)                     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

Figure 14: Extension Field Format

图14:扩展字段格式

All extension fields are zero-padded to a word (four octets) boundary. The Field Type field is specific to the defined function and is not elaborated here. While the minimum field length containing required fields is four words (16 octets), a maximum field length remains to be established.

所有扩展字段都以零填充到一个字(四个八位字节)边界。字段类型字段特定于已定义的函数,此处不再详述。虽然包含所需字段的最小字段长度为四个字(16个八位字节),但最大字段长度仍有待确定。

The Length field is a 16-bit unsigned integer that indicates the length of the entire extension field in octets, including the Padding field.

长度字段是一个16位无符号整数,以八位字节表示整个扩展字段的长度,包括填充字段。

8. On-Wire Protocol
8. 在线协议

The heart of the NTP on-wire protocol is the core mechanism that exchanges time values between servers, peers, and clients. It is inherently resistant to lost or duplicate packets. Data integrity is provided by the IP and UDP checksums. No flow control or retransmission facilities are provided or necessary. The protocol uses timestamps, which are either extracted from packet headers or struck from the system clock upon the arrival or departure of a packet. Timestamps are precision data and should be restruck in the case of link-level retransmission and corrected for the time to compute a MAC in transmit.

NTP在线协议的核心是在服务器、对等机和客户端之间交换时间值的核心机制。它固有地抵抗丢失或重复的数据包。数据完整性由IP和UDP校验和提供。未提供或不需要流量控制或重传设施。该协议使用时间戳,时间戳可以从数据包头中提取,也可以在数据包到达或离开时从系统时钟中触发。时间戳是精确的数据,在链路级重传的情况下应重新锁定,并在传输中计算MAC的时间内进行校正。

NTP messages make use of two different communication modes, one-to-one and one-to-many, commonly referred to as unicast and broadcast. For the purposes of this document, the term broadcast is interpreted as any available one-to-many mechanism. For IPv4, this equates to either IPv4 broadcast or IPv4 multicast. For IPv6, this equates to IPv6 multicast. For this purpose, IANA has allocated the IPv4 multicast address 224.0.1.1 and the IPv6 multicast address ending :101, with the prefix determined by scoping rules. Any other non-allocated multicast address may also be used in addition to these allocated multicast addresses.

NTP消息使用两种不同的通信模式,一对一和一对多,通常称为单播和广播。在本文件中,术语广播被解释为任何可用的一对多机制。对于IPv4,这相当于IPv4广播或IPv4多播。对于IPv6,这等同于IPv6多播。为此,IANA分配了IPv4多播地址224.0.1.1和IPv6多播地址结尾101,前缀由作用域规则确定。除了这些已分配的多播地址之外,还可以使用任何其他未分配的多播地址。

The on-wire protocol uses four timestamps numbered t1 through t4 and three state variables org, rec, and xmt, as shown in Figure 15. This figure shows the most general case where each of two peers, A and B, independently measure the offset and delay relative to the other. For purposes of illustration, the packet timestamps are shown in lowercase, while the state variables are shown in uppercase. The state variables are copied from the packet timestamps upon arrival or departure of a packet.

在线协议使用四个编号为t1到t4的时间戳和三个状态变量org、rec和xmt,如图15所示。此图显示了两个对等点(A和B)各自独立测量相对于另一个的偏移和延迟的最一般情况。为了便于说明,数据包时间戳以小写字母显示,而状态变量以大写字母显示。在数据包到达或离开时,从数据包时间戳复制状态变量。

             t2            t3           t6            t7
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t1   |   |   t3    |   |    t5   |
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t2   |   |   t4    |   |    t6   |  Packet
        +---------+   +---------+   +---------+   +---------+ Timestamps
        |   t1    |   |t3=clock |   |   t5    |   |t7=clock |
        +---------+   +---------+   +---------+   +---------+
        |t2=clock |                 |t6=clock |
        +---------+                 +---------+
                                                               Peer B
        +---------+   +---------+   +---------+   +---------+
   org  |   T1    |   |    T1   |   | t5<>T1? |   |    T5   |
        +---------+   +---------+   +---------+   +---------+   State
   rec  |   T2    |   |    T2   |   |   T6    |   |    T6   | Variables
        +---------+   +---------+   +---------+   +---------+
   xmt  |    0    |   |    T3   |   |  t3=T3? |   |    T7   |
        +---------+   +---------+   +---------+   +---------+
        
             t2            t3           t6            t7
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t1   |   |   t3    |   |    t5   |
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t2   |   |   t4    |   |    t6   |  Packet
        +---------+   +---------+   +---------+   +---------+ Timestamps
        |   t1    |   |t3=clock |   |   t5    |   |t7=clock |
        +---------+   +---------+   +---------+   +---------+
        |t2=clock |                 |t6=clock |
        +---------+                 +---------+
                                                               Peer B
        +---------+   +---------+   +---------+   +---------+
   org  |   T1    |   |    T1   |   | t5<>T1? |   |    T5   |
        +---------+   +---------+   +---------+   +---------+   State
   rec  |   T2    |   |    T2   |   |   T6    |   |    T6   | Variables
        +---------+   +---------+   +---------+   +---------+
   xmt  |    0    |   |    T3   |   |  t3=T3? |   |    T7   |
        +---------+   +---------+   +---------+   +---------+
        
                  t2      t3                 t6          t7
        ---------------------------------------------------------
                 /\         \                 /\            \
                 /           \                /              \
                /             \              /                \
               /               \/           /                 \/
        ---------------------------------------------------------
             t1                t4         t5                  t8
        
                  t2      t3                 t6          t7
        ---------------------------------------------------------
                 /\         \                 /\            \
                 /           \                /              \
                /             \              /                \
               /               \/           /                 \/
        ---------------------------------------------------------
             t1                t4         t5                  t8
        
            t1            t4            t5             t8
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t1   |   |   t3    |   |    t5   |
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t2   |   |   t4    |   |    t6   |  Packet
        +---------+   +---------+   +---------+   +---------+ Timestamps
        |t1=clock |   |    t3   |   |t5=clock |   |    t7   |
        +---------+   +---------+   +---------+   +---------+
                      |t4=clock |                 |t8=clock |
                      +---------+                 +---------+
                                                               Peer A
        +---------+   +---------+   +---------+   +---------+
   org  |    0    |   |  t3<>0? |   |   T3    |   | t7<>T3? |
        +---------+   +---------+   +---------+   +---------+   State
   rec  |    0    |   |    T4   |   |   T4    |   |    T8   | Variables
        +---------+   +---------+   +---------+   +---------+
   xmt  |   T1    |   |  t1=T1? |   |   T5    |   |  t5=T5? |
        +---------+   +---------+   +---------+   +---------+
        
            t1            t4            t5             t8
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t1   |   |   t3    |   |    t5   |
        +---------+   +---------+   +---------+   +---------+
        |    0    |   |    t2   |   |   t4    |   |    t6   |  Packet
        +---------+   +---------+   +---------+   +---------+ Timestamps
        |t1=clock |   |    t3   |   |t5=clock |   |    t7   |
        +---------+   +---------+   +---------+   +---------+
                      |t4=clock |                 |t8=clock |
                      +---------+                 +---------+
                                                               Peer A
        +---------+   +---------+   +---------+   +---------+
   org  |    0    |   |  t3<>0? |   |   T3    |   | t7<>T3? |
        +---------+   +---------+   +---------+   +---------+   State
   rec  |    0    |   |    T4   |   |   T4    |   |    T8   | Variables
        +---------+   +---------+   +---------+   +---------+
   xmt  |   T1    |   |  t1=T1? |   |   T5    |   |  t5=T5? |
        +---------+   +---------+   +---------+   +---------+
        

Figure 15: On-Wire Protocol

图15:在线协议

In the figure, the first packet transmitted by A contains only the origin timestamp t1, which is then copied to T1. B receives the packet at t2 and copies t1 to T1 and the receive timestamp t2 to T2. At this time or some time later at t3, B sends a packet to A containing t1 and t2 and the transmit timestamp t3. All three timestamps are copied to the corresponding state variables. A receives the packet at t4 containing the three timestamps t1, t2, and t3 and the destination timestamp t4. These four timestamps are used to compute the offset and delay of B relative to A, as described below.

在图中,A发送的第一个数据包仅包含原始时间戳t1,然后将原始时间戳t1复制到t1。B在t2处接收分组,并将t1复制到t1以及接收时间戳t2复制到t2。此时或稍后某个时间在t3,B向a发送包含t1和t2以及发送时间戳t3的分组。所有三个时间戳都复制到相应的状态变量。A在t4接收包含三个时间戳t1、t2和t3以及目的地时间戳t4的分组。这四个时间戳用于计算B相对于A的偏移量和延迟,如下所述。

Before the xmt and org state variables are updated, two sanity checks are performed in order to protect against duplicate, bogus, or replayed packets. In the exchange above, a packet is duplicate or replay if the transmit timestamp t3 in the packet matches the org state variable T3. A packet is bogus if the origin timestamp t1 in the packet does not match the xmt state variable T1. In either of these cases, the state variables are updated, then the packet is discarded. To protect against replay of the last transmitted packet, the xmt state variable is set to zero immediately after a successful bogus check.

在更新xmt和org状态变量之前,将执行两个健全性检查,以防止重复、伪造或重播数据包。在上述交换中,如果分组中的发送时间戳t3与组织状态变量t3匹配,则分组是重复的或重放的。如果数据包中的原始时间戳t1与xmt状态变量t1不匹配,则数据包是假的。在这两种情况中,状态变量被更新,然后数据包被丢弃。为了防止重播最后传输的数据包,在成功的伪检查后,xmt状态变量立即设置为零。

The four most recent timestamps, T1 through T4, are used to compute the offset of B relative to A

最近的四个时间戳T1到T4用于计算B相对于A的偏移量

   theta = T(B) - T(A) = 1/2 * [(T2-T1) + (T3-T4)]
        
   theta = T(B) - T(A) = 1/2 * [(T2-T1) + (T3-T4)]
        

and the round-trip delay

还有往返的延误

   delta = T(ABA) = (T4-T1) - (T3-T2).
        
   delta = T(ABA) = (T4-T1) - (T3-T2).
        

Note that the quantities within parentheses are computed from 64-bit unsigned timestamps and result in signed values with 63 significant bits plus sign. These values can represent dates from 68 years in the past to 68 years in the future. However, the offset and delay are computed as sums and differences of these values, which contain 62 significant bits and two sign bits, so they can represent unambiguous values from 34 years in the past to 34 years in the future. In other words, the time of the client must be set within 34 years of the server before the service is started. This is a fundamental limitation with 64-bit integer arithmetic.

请注意,括号内的数量是根据64位无符号时间戳计算得出的,结果是有符号值带有63个有效位加号。这些值可以表示从过去68年到未来68年的日期。然而,偏移和延迟被计算为这些值的总和和差值,其中包含62个有效位和两个符号位,因此它们可以表示从过去34年到未来34年的明确值。换句话说,客户机的时间必须设置在服务器启动前的34年内。这是64位整数算法的一个基本限制。

In implementations where floating double arithmetic is available, the first-order differences can be converted to floating double and the second-order sums and differences computed in that arithmetic. Since

在可使用浮点双精度运算的实现中,一阶差可以转换为浮点双精度运算,二阶和和和差可以在该运算中计算。自从

the second-order terms are typically very small relative to the timestamp magnitudes, there is no loss in significance, yet the unambiguous range is restored from 34 years to 68 years.

二阶项相对于时间戳震级通常非常小,没有显著性损失,但明确的范围从34年恢复到68年。

In some scenarios where the initial frequency offset of the client is relatively large and the actual propagation time small, it is possible for the delay computation to become negative. For instance, if the frequency difference is 100 ppm and the interval T4-T1 is 64 s, the apparent delay is -6.4 ms. Since negative values are misleading in subsequent computations, the value of delta should be clamped not less than s.rho, where s.rho is the system precision described in Section 11.1, expressed in seconds.

在客户端的初始频率偏移相对较大且实际传播时间较小的一些场景中,延迟计算可能变为负值。例如,如果频率差为100 ppm,间隔T4-T1为64 s,则视在延迟为-6.4 ms。由于负值在后续计算中会产生误导,因此δ值应不小于s.rho,其中s.rho是第11.1节中描述的系统精度,以秒为单位。

The discussion above assumes the most general case where two symmetric peers independently measure the offsets and delays between them. In the case of a stateless server, the protocol can be simplified. A stateless server copies T3 and T4 from the client packet to T1 and T2 of the server packet and tacks on the transmit timestamp T3 before sending it to the client. Additional details for filling in the remaining protocol fields are given in a Section 9 and following sections and in the appendix.

上面的讨论假设了两个对称对等点独立测量它们之间的偏移和延迟的最一般情况。对于无状态服务器,可以简化协议。无状态服务器将T3和T4从客户端分组复制到服务器分组的T1和T2,并在发送到客户端之前固定发送时间戳T3。第9节和后续章节以及附录中给出了填写剩余协议字段的其他详细信息。

Note that the on-wire protocol as described resists replay of a server response packet. However, it does not resist replay of the client request packet, which would result in a server reply packet with new values of T2 and T3 and result in incorrect offset and delay. This vulnerability can be avoided by setting the xmt state variable to zero after computing the offset and delay.

请注意,如上所述的在线协议阻止服务器响应数据包的重播。但是,它不会阻止客户机请求数据包的重播,这将导致服务器应答数据包的新值为T2和T3,并导致不正确的偏移量和延迟。通过在计算偏移量和延迟后将xmt状态变量设置为零,可以避免此漏洞。

9. Peer Process
9. 对等进程

The process descriptions to follow include a listing of the important state variables followed by an overview of the process operations implemented as routines. Frequent reference is made to the skeleton in the appendix. The skeleton includes C-language fragments that describe the functions in more detail. It includes the parameters, variables, and declarations necessary for a conforming NTPv4 implementation. However, many additional variables and routines may be necessary in a working implementation.

接下来的过程描述包括重要状态变量的列表,以及作为例程实现的过程操作的概述。附录中经常提到骨架。该框架包括更详细地描述函数的C语言片段。它包括符合NTPv4实现所需的参数、变量和声明。然而,在工作实现中可能需要许多额外的变量和例程。

The peer process is called upon arrival of a server or peer packet. It runs the on-wire protocol to determine the clock offset and round-trip delay and computes statistics used by the system and poll processes. Peer variables are instantiated in the association data structure when the structure is initialized and updated by arriving packets. There is a peer process, poll process, and association process for each server.

对等进程在服务器或对等数据包到达时调用。它运行在线协议以确定时钟偏移和往返延迟,并计算系统和轮询进程使用的统计数据。当通过到达的数据包初始化和更新结构时,在关联数据结构中实例化对等变量。每个服务器都有一个对等进程、轮询进程和关联进程。

9.1. Peer Process Variables
9.1. 对等过程变量

Figures 16, 17, 18, and 19 summarize the common names, formula names, and a short description of the peer variables. The common names and formula names are interchangeable; formula names are intended to increase readability of equations in this specification. Unless noted otherwise, all peer variables have assumed prefix p.

图16、17、18和19总结了常见名称、公式名称以及对等变量的简短描述。通用名称和公式名称可互换;公式名称旨在增加本规范中公式的可读性。除非另有说明,否则所有对等变量均采用前缀p。

                 +---------+----------+-----------------------+
                 | Name    | Formula  | Description           |
                 +---------+----------+-----------------------+
                 | srcaddr | srcaddr  | source address        |
                 | srcport | srcport  | source port           |
                 | dstaddr | dstaddr  | destination address   |
                 | dstport | destport | destination port      |
                 | keyid   | keyid    | key identifier key ID |
                 +---------+----------+-----------------------+
        
                 +---------+----------+-----------------------+
                 | Name    | Formula  | Description           |
                 +---------+----------+-----------------------+
                 | srcaddr | srcaddr  | source address        |
                 | srcport | srcport  | source port           |
                 | dstaddr | dstaddr  | destination address   |
                 | dstport | destport | destination port      |
                 | keyid   | keyid    | key identifier key ID |
                 +---------+----------+-----------------------+
        

Figure 16: Peer Process Configuration Variables

图16:对等进程配置变量

                +-----------+------------+---------------------+
                | Name      | Formula    | Description         |
                +-----------+------------+---------------------+
                | leap      | leap       | leap indicator      |
                | version   | version    | version number      |
                | mode      | mode       | mode                |
                | stratum   | stratum    | stratum             |
                | ppoll     | ppoll      | peer poll exponent  |
                | rootdelay | delta_r    | root delay          |
                | rootdisp  | epsilon_r  | root dispersion     |
                | refid     | refid      | reference ID        |
                | reftime   | reftime    | reference timestamp |
                +-----------+------------+---------------------+
        
                +-----------+------------+---------------------+
                | Name      | Formula    | Description         |
                +-----------+------------+---------------------+
                | leap      | leap       | leap indicator      |
                | version   | version    | version number      |
                | mode      | mode       | mode                |
                | stratum   | stratum    | stratum             |
                | ppoll     | ppoll      | peer poll exponent  |
                | rootdelay | delta_r    | root delay          |
                | rootdisp  | epsilon_r  | root dispersion     |
                | refid     | refid      | reference ID        |
                | reftime   | reftime    | reference timestamp |
                +-----------+------------+---------------------+
        

Figure 17: Peer Process Packet Variables

图17:对等进程数据包变量

                     +------+---------+--------------------+
                     | Name | Formula | Description        |
                     +------+---------+--------------------+
                     | org  | T1      | origin timestamp   |
                     | rec  | T2      | receive timestamp  |
                     | xmt  | T3      | transmit timestamp |
                     | t    | t       | packet time        |
                     +------+---------+--------------------+
        
                     +------+---------+--------------------+
                     | Name | Formula | Description        |
                     +------+---------+--------------------+
                     | org  | T1      | origin timestamp   |
                     | rec  | T2      | receive timestamp  |
                     | xmt  | T3      | transmit timestamp |
                     | t    | t       | packet time        |
                     +------+---------+--------------------+
        

Figure 18: Peer Process Timestamp Variables

图18:对等进程时间戳变量

                     +--------+---------+-----------------+
                     | Name   | Formula | Description     |
                     +--------+---------+-----------------+
                     | offset | theta   | clock offset    |
                     | delay  | delta   | round-trip delay|
                     | disp   | epsilon | dispersion      |
                     | jitter | psi     | jitter          |
                     | filter | filter  | clock filter    |
                     | tp     | t_p     | filter time     |
                     +--------+---------+-----------------+
        
                     +--------+---------+-----------------+
                     | Name   | Formula | Description     |
                     +--------+---------+-----------------+
                     | offset | theta   | clock offset    |
                     | delay  | delta   | round-trip delay|
                     | disp   | epsilon | dispersion      |
                     | jitter | psi     | jitter          |
                     | filter | filter  | clock filter    |
                     | tp     | t_p     | filter time     |
                     +--------+---------+-----------------+
        

Figure 19: Peer Process Statistics Variables

图19:对等进程统计变量

The following configuration variables are normally initialized when the association is mobilized, either from a configuration file or upon the arrival of the first packet for an unknown association.

以下配置变量通常在从配置文件或未知关联的第一个数据包到达时启动关联时初始化。

srcaddr: IP address of the remote server or reference clock. This becomes the destination IP address in packets sent from this association.

srcadr:远程服务器或参考时钟的IP地址。这将成为从该关联发送的数据包中的目标IP地址。

srcport: UDP port number of the server or reference clock. This becomes the destination port number in packets sent from this association. When operating in symmetric modes (1 and 2), this field must contain the NTP port number PORT (123) assigned by the IANA. In other modes, it can contain any number consistent with local policy.

srcport:服务器或参考时钟的UDP端口号。这将成为从此关联发送的数据包中的目标端口号。在对称模式(1和2)下运行时,此字段必须包含IANA分配的NTP端口号端口(123)。在其他模式下,它可以包含与本地策略一致的任何数字。

dstaddr: IP address of the client. This becomes the source IP address in packets sent from this association.

dstaddr:客户端的IP地址。这将成为从该关联发送的数据包中的源IP地址。

dstport: UDP port number of the client, ordinarily the NTP port number PORT (123) assigned by the IANA. This becomes the source port number in packets sent from this association.

dstport:客户端的UDP端口号,通常是IANA分配的NTP端口号端口(123)。这将成为从此关联发送的数据包中的源端口号。

keyid: Symmetric key ID for the 128-bit MD5 key used to generate and verify the MAC. The client and server or peer can use different values, but they must map to the same key.

keyid:用于生成和验证MAC的128位MD5密钥的对称密钥ID。客户端和服务器或对等方可以使用不同的值,但它们必须映射到同一个密钥。

The variables defined in Figure 17 are updated from the packet header as each packet arrives. They are interpreted in the same way as the packet variables of the same names. It is convenient for later processing to convert the NTP short format packet values r.rootdelay and r.rootdisp to floating doubles as peer variables.

图17中定义的变量在每个数据包到达时从数据包头更新。它们的解释方式与同名的数据包变量相同。将NTP短格式数据包值r.rootdelay和r.rootdisp转换为浮动双精度作为对等变量,便于后续处理。

The variables defined in Figure 18 include the timestamps exchanged by the on-wire protocol in Section 8. The t variable is the seconds counter c.t associated with these values. The c.t variable is maintained by the clock-adjust process described in Section 12. It

图18中定义的变量包括第8节中在线协议交换的时间戳。t变量是与这些值相关联的秒计数器c.t。c.t变量由第12节所述的时钟调整过程维持。信息技术

counts the seconds since the service was started. The variables defined in Figure 19 include the statistics computed by the clock_filter() routine described in Section 10. The tp variable is the seconds counter associated with these values.

统计自服务启动以来的秒数。图19中定义的变量包括由第10节中描述的clock_filter()例程计算的统计信息。tp变量是与这些值关联的秒计数器。

9.2. Peer Process Operations
9.2. 对等进程操作

The receive routine defines the process flow upon the arrival of a packet. An example is described by the receive() routine in Appendix A.5.1. There is no specific method required for access control, although it is recommended that implementations include such a scheme, which is similar to many others now in widespread use. The access() routine in Appendix A.5.4 describes a method of implementing access restrictions using an access control list (ACL). Format checks require correct field length and alignment, acceptable version number (1-4), and correct extension field syntax, if present.

接收例程定义数据包到达时的处理流程。附录A.5.1中的receive()例程描述了一个示例。访问控制不需要特定的方法,尽管建议实现包括这样的方案,这类似于现在广泛使用的许多其他方案。附录A.5.4中的access()例程描述了使用访问控制列表(ACL)实现访问限制的方法。格式检查需要正确的字段长度和对齐方式、可接受的版本号(1-4)和正确的扩展字段语法(如果存在)。

There is no specific requirement for authentication; however, if authentication is implemented, then the MD5-keyed hash algorithm described in [RFC1321] must be supported.

对认证没有具体要求;但是,如果实现了身份验证,则必须支持[RFC1321]中描述的MD5键控哈希算法。

Next, the association table is searched for matching source address and source port, for example, using the find_assoc() routine in Appendix A.5.1. Figure 20 is a dispatch table where the columns correspond to the packet mode and rows correspond to the association mode. The intersection of the association and packet modes dispatches processing to one of the following steps.

接下来,使用附录A.5.1中的find_assoc()例程,在关联表中搜索匹配的源地址和源端口。图20是一个调度表,其中列对应于数据包模式,行对应于关联模式。关联和数据包模式的交集将处理分派到以下步骤之一。

           +------------------+---------------------------------------+
           |                  |              Packet Mode              |
           +------------------+-------+-------+-------+-------+-------+
           | Association Mode |   1   |   2   |   3   |   4   |   5   |
           +------------------+-------+-------+-------+-------+-------+
           | No Association 0 | NEWPS | DSCRD | FXMIT | MANY  | NEWBC |
           | Symm. Active   1 | PROC  | PROC  | DSCRD | DSCRD | DSCRD |
           | Symm. Passive  2 | PROC  | ERR   | DSCRD | DSCRD | DSCRD |
           | Client         3 | DSCRD | DSCRD | DSCRD | PROC  | DSCRD |
           | Server         4 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
           | Broadcast      5 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
           | Bcast Client   6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC  |
           +------------------+-------+-------+-------+-------+-------+
        
           +------------------+---------------------------------------+
           |                  |              Packet Mode              |
           +------------------+-------+-------+-------+-------+-------+
           | Association Mode |   1   |   2   |   3   |   4   |   5   |
           +------------------+-------+-------+-------+-------+-------+
           | No Association 0 | NEWPS | DSCRD | FXMIT | MANY  | NEWBC |
           | Symm. Active   1 | PROC  | PROC  | DSCRD | DSCRD | DSCRD |
           | Symm. Passive  2 | PROC  | ERR   | DSCRD | DSCRD | DSCRD |
           | Client         3 | DSCRD | DSCRD | DSCRD | PROC  | DSCRD |
           | Server         4 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
           | Broadcast      5 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
           | Bcast Client   6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC  |
           +------------------+-------+-------+-------+-------+-------+
        

Figure 20: Peer Dispatch Table

图20:对等调度表

DSCRD. This indicates a non-fatal violation of protocol as the result of a programming error, long-delayed packet, or replayed packet. The peer process discards the packet and exits.

DSCRD。这表示由于编程错误、长时间延迟的数据包或重播的数据包而导致的非致命性协议违反。对等进程丢弃数据包并退出。

ERR. This indicates a fatal violation of protocol as the result of a programming error, long-delayed packet, or replayed packet. The peer process discards the packet, demobilizes the symmetric passive association, and exits.

犯错误这表示由于编程错误、长时间延迟的数据包或重播的数据包导致严重违反协议。对等进程丢弃数据包,解除对称被动关联,然后退出。

FXMIT. This indicates a client (mode 3) packet matching no association (mode 0). If the destination address is not a broadcast address, the server constructs a server (mode 4) packet and returns it to the client without retaining state. The server packet header is constructed. An example is described by the fast_xmit() routine in Appendix A.5.3. The packet header is assembled from the receive packet and system variables as shown in Figure 21. If the s.rootdelay and s.rootdisp system variables are stored in floating double, they must be converted to NTP short format first.

FXMIT。这表示客户端(模式3)数据包不匹配任何关联(模式0)。如果目标地址不是广播地址,则服务器构造一个服务器(模式4)数据包并将其返回给客户端,而不保留状态。构造了服务器数据包头。附录A.5.3中的fast_xmit()例程描述了一个示例。数据包头由接收数据包和系统变量组合而成,如图21所示。如果s.rootdelay和s.rootdisp系统变量以浮点双精度存储,则必须首先将它们转换为NTP短格式。

                   +-----------------------------------+
                   | Packet Variable -->   Variable    |
                   +-----------------------------------+
                   | r.leap        -->     p.leap      |
                   | r.mode        -->     p.mode      |
                   | r.stratum     -->     p.stratum   |
                   | r.poll        -->     p.ppoll     |
                   | r.rootdelay   -->     p.rootdelay |
                   | r.rootdisp    -->     p.rootdisp  |
                   | r.refid       -->     p.refid     |
                   | r.reftime     -->     p.reftime   |
                   | r.keyid       -->     p.keyid     |
                   +-----------------------------------+
        
                   +-----------------------------------+
                   | Packet Variable -->   Variable    |
                   +-----------------------------------+
                   | r.leap        -->     p.leap      |
                   | r.mode        -->     p.mode      |
                   | r.stratum     -->     p.stratum   |
                   | r.poll        -->     p.ppoll     |
                   | r.rootdelay   -->     p.rootdelay |
                   | r.rootdisp    -->     p.rootdisp  |
                   | r.refid       -->     p.refid     |
                   | r.reftime     -->     p.reftime   |
                   | r.keyid       -->     p.keyid     |
                   +-----------------------------------+
        

Figure 21: Receive Packet Header

图21:接收数据包头

Note that, if authentication fails, the server returns a special message called a crypto-NAK. This message includes the normal NTP header data shown in Figure 8, but with a MAC consisting of four octets of zeros. The client MAY accept or reject the data in the message. After these actions, the peer process exits.

注意,如果身份验证失败,服务器将返回一条称为crypto-NAK的特殊消息。此消息包括图8所示的正常NTP报头数据,但MAC由四个八位字节组成。客户端可以接受或拒绝消息中的数据。执行这些操作后,对等进程退出。

If the destination address is a multicast address, the sender is operating in manycast client mode. If the packet is valid and the server stratum is less than the client stratum, the server sends an ordinary server (mode 4) packet, but one which uses its unicast destination address. A crypto-NAK is not sent if authentication fails. After these actions, the peer process exits.

如果目标地址是多播地址,则发送方在多播客户端模式下运行。如果数据包有效且服务器层小于客户层,则服务器发送一个普通服务器(模式4)数据包,但该数据包使用其单播目的地地址。如果身份验证失败,则不会发送加密NAK。执行这些操作后,对等进程退出。

MANY: This indicates a server (mode 4) packet matching no association. Ordinarily, this can happen only as the result of a manycast server reply to a previously sent multicast client packet.

多:这表示没有关联的服务器(模式4)数据包匹配。通常,这只能在manycast服务器回复之前发送的多播客户端数据包后发生。

If the packet is valid, an ordinary client (mode 3) association is mobilized and operation continues as if the association was mobilized by the configuration file.

如果数据包有效,则会激活普通客户端(模式3)关联,并且操作将继续,就像该关联是由配置文件激活的一样。

NEWBC. This indicates a broadcast (mode 5) packet matching no association. The client mobilizes either a client (mode 3) or broadcast client (mode 6) association. Examples are shown in the mobilize() and clear() routines in Appendix A.2. Then, the packet is validated and the peer variables initialized. An example is provided by the packet() routine in Appendix A.5.1.1.

纽伯克。这表示广播(模式5)数据包不匹配关联。客户端移动客户端(模式3)或广播客户端(模式6)关联。示例如附录A.2中的Movesite()和clear()例程所示。然后,验证数据包并初始化对等变量。附录A.5.1.1中的packet()例程提供了一个示例。

If the implementation supports no additional security or calibration functions, the association mode is set to broadcast client (mode 6) and the peer process exits. Implementations supporting public key authentication MAY run the Autokey or equivalent security protocol. Implementations SHOULD set the association mode to 3 and run a short client/server exchange to determine the propagation delay. Following the exchange, the association mode is set to 6 and the peer process continues in listen-only mode. Note the distinction between a mode-6 packet, which is reserved for the NTP monitor and control functions, and a mode-6 association.

如果实现不支持其他安全或校准功能,则关联模式设置为广播客户端(模式6),对等进程退出。支持公钥身份验证的实现可以运行自动密钥或等效的安全协议。实现应将关联模式设置为3,并运行短的客户端/服务器交换来确定传播延迟。交换之后,关联模式设置为6,对等进程继续以仅侦听模式进行。注意为NTP监视和控制功能保留的模式6数据包与模式6关联之间的区别。

NEWPS. This indicates a symmetric active (mode 1) packet matching no association. The client mobilizes a symmetric passive (mode 2) association. An example is shown in the mobilize() and clear() routines in Appendix A.2. Processing continues in the PROC section below.

纽普斯。这表示对称活动(模式1)数据包不匹配任何关联。客户端移动对称被动(模式2)关联。附录A.2中的Movesite()和clear()例程中显示了一个示例。处理将在下面的过程部分继续。

PROC. This indicates a packet matching an existing association. The packet timestamps are carefully checked to avoid invalid, duplicate, or bogus packets. Additional checks are summarized in Figure 22. Note that all packets, including a crypto-NAK, are considered valid only if they survive these tests.

过程。这表示与现有关联匹配的数据包。仔细检查数据包时间戳,以避免无效、重复或伪造数据包。图22总结了其他检查。请注意,所有数据包,包括加密NAK,只有在通过这些测试后才被视为有效。

   +--------------------------+----------------------------------------+
   | Packet Type              | Description                            |
   +--------------------------+----------------------------------------+
   | 1 duplicate packet       | The packet is at best an old duplicate |
   |                          | or at worst a replay by a hacker.      |
   |                          | This can happen in symmetric modes if  |
   |                          | the poll intervals are uneven.         |
   | 2 bogus packet           |                                        |
   | 3 invalid                | One or more timestamp fields are       |
   |                          | invalid. This normally happens in      |
   |                          | symmetric modes when one peer sends    |
   |                          | the first packet to the other and      |
   |                          | before the other has received its      |
   |                          | first reply.                           |
   | 4 access denied          | The access controls have blacklisted   |
   |                          | the source.                            |
   | 5 authentication failure | The cryptographic message digest does  |
   |                          | not match the MAC.                     |
   | 6 unsynchronized         | The server is not synchronized to a    |
   |                          | valid source.                          |
   | 7 bad header data        | One or more header fields are invalid. |
   +--------------------------+----------------------------------------+
        
   +--------------------------+----------------------------------------+
   | Packet Type              | Description                            |
   +--------------------------+----------------------------------------+
   | 1 duplicate packet       | The packet is at best an old duplicate |
   |                          | or at worst a replay by a hacker.      |
   |                          | This can happen in symmetric modes if  |
   |                          | the poll intervals are uneven.         |
   | 2 bogus packet           |                                        |
   | 3 invalid                | One or more timestamp fields are       |
   |                          | invalid. This normally happens in      |
   |                          | symmetric modes when one peer sends    |
   |                          | the first packet to the other and      |
   |                          | before the other has received its      |
   |                          | first reply.                           |
   | 4 access denied          | The access controls have blacklisted   |
   |                          | the source.                            |
   | 5 authentication failure | The cryptographic message digest does  |
   |                          | not match the MAC.                     |
   | 6 unsynchronized         | The server is not synchronized to a    |
   |                          | valid source.                          |
   | 7 bad header data        | One or more header fields are invalid. |
   +--------------------------+----------------------------------------+
        

Figure 22: Packet Error Checks

图22:数据包错误检查

Processing continues by copying the packet variables to the peer variables as shown in Figure 21. An example is described by the packet() routine in Appendix A.5.1.1. The receive() routine implements tests 1-5 in Figure 22; the packet() routine implements tests 6-7. If errors are found, the packet is discarded and the peer process exits.

处理通过将数据包变量复制到对等变量来继续,如图21所示。附录A.5.1.1中的packet()例程描述了一个示例。receive()例程实现图22中的测试1-5;packet()例程实现测试6-7。如果发现错误,则丢弃数据包并退出对等进程。

The on-wire protocol calculates the clock offset theta and round-trip delay delta from the four most recent timestamps as described in Section 8. While it is, in principle, possible to do all calculations except the first-order timestamp differences in fixed-point arithmetic, it is much easier to convert the first-order differences to floating doubles and do the remaining calculations in that arithmetic, and this will be assumed in the following description.

在线协议根据第8节中描述的四个最新时间戳计算时钟偏移θ和往返延迟增量。虽然原则上可以在定点算法中进行除一阶时间戳差以外的所有计算,但将一阶差转换为浮点双精度并在该算法中进行其余计算要容易得多,这将在下面的描述中假设。

Next, the 8-bit p.reach shift register in the poll process described in Section 13 is used to determine whether the server is reachable and the data are fresh. The register is shifted left by one bit when a packet is sent and the rightmost bit is set to zero. As valid packets arrive, the rightmost bit is set to one. If the register contains any nonzero bits, the server is considered reachable; otherwise, it is unreachable. Since the peer poll interval might

接下来,使用第13节中描述的轮询过程中的8位p.reach移位寄存器来确定服务器是否可访问以及数据是否新鲜。发送数据包时,寄存器左移一位,最右边的位设为零。当有效数据包到达时,最右边的位被设置为1。如果寄存器包含任何非零位,则认为服务器是可访问的;否则,它是无法到达的。因为对等轮询间隔可能

have changed since the last packet, the host poll interval is reviewed. An example is provided by the poll_update() routine in Appendix A.5.7.2.

自上次数据包更改后,主机轮询间隔将被复查。附录A.5.7.2中的poll_update()例程提供了一个示例。

The dispersion statistic epsilon(t) represents the maximum error due to the frequency tolerance and time since the last packet was sent. It is initialized

色散统计ε(t)表示自发送最后一个数据包以来由于频率容差和时间引起的最大误差。它已初始化

   epsilon(t_0) = r.rho + s.rho + PHI * (T4-T1)
        
   epsilon(t_0) = r.rho + s.rho + PHI * (T4-T1)
        

when the measurement is made at t_0 according to the seconds counter. Here, r.rho is the packet precision described in Section 7.3 and s.rho is the system precision described in Section 11.1, both expressed in seconds. These terms are necessary to account for the uncertainty in reading the system clock in both the server and the client.

当根据秒计数器在t_0进行测量时。这里,r.rho是第7.3节中描述的数据包精度,s.rho是第11.1节中描述的系统精度,两者均以秒表示。这些术语对于解释在服务器和客户机中读取系统时钟的不确定性是必需的。

The dispersion then grows at constant rate PHI; in other words, at time t, epsilon(t) = epsilon(t_0) + PHI * (t-t_0). With the default value PHI = 15 ppm, this amounts to about 1.3 s per day. With this understanding, the argument t will be dropped and the dispersion represented simply as epsilon. The remaining statistics are computed by the clock filter algorithm described in the next section.

然后,色散以恒定速率φ增长;换句话说,在时间t,ε(t)=ε(t_0)+φ*(t-t_0)。在默认值PHI=15 ppm的情况下,这相当于每天约1.3秒。有了这种理解,参数t将被删除,离散度将简单地表示为ε。剩余的统计数据由下一节中描述的时钟滤波器算法计算。

10. Clock Filter Algorithm
10. 时钟滤波算法

The clock filter algorithm is part of the peer process. It grooms the stream of on-wire data to select the samples most likely to represent accurate time. The algorithm produces the variables shown in Figure 19, including the offset (theta), delay (delta), dispersion (epsilon), jitter (psi), and time of arrival (t). These data are used by the mitigation algorithms to determine the best and final offset used to discipline the system clock. They are also used to determine the server health and whether it is suitable for synchronization.

时钟滤波器算法是对等进程的一部分。它梳理在线数据流,以选择最有可能代表准确时间的样本。该算法产生如图19所示的变量,包括偏移量(θ)、延迟(δ)、色散(ε)、抖动(psi)和到达时间(t)。缓解算法使用这些数据来确定用于调节系统时钟的最佳和最终偏移量。它们还用于确定服务器运行状况以及是否适合同步。

The clock filter algorithm saves the most recent sample tuples (theta, delta, epsilon, t) in the filter structure, which functions as an 8-stage shift register. The tuples are saved in the order that packets arrive. Here, t is the packet time of arrival according to the seconds counter and should not be confused with the peer variable tp.

时钟滤波器算法将最新的样本元组(θ、δ、ε、t)保存在滤波器结构中,该结构起到8级移位寄存器的作用。元组按数据包到达的顺序保存。这里,t是根据秒计数器的分组到达时间,不应与对等变量tp混淆。

The following scheme is used to ensure sufficient samples are in the filter and that old stale data are discarded. Initially, the tuples of all stages are set to the dummy tuple (0, MAXDISP, MAXDISP, 0). As valid packets arrive, tuples are shifted into the filter causing old tuples to be discarded, so eventually only valid tuples remain.

以下方案用于确保过滤器中有足够的样本,并丢弃旧的过时数据。最初,所有阶段的元组都设置为伪元组(0,MAXDISP,MAXDISP,0)。当有效数据包到达时,元组被转移到过滤器中,导致旧元组被丢弃,因此最终只剩下有效元组。

If the three low-order bits of the reach register are zero, indicating three poll intervals have expired with no valid packets received, the poll process calls the clock filter algorithm with a dummy tuple just as if the tuple had arrived from the network. If this persists for eight poll intervals, the register returns to the initial condition.

如果reach寄存器的三个低阶位为零,表示三个轮询间隔已过期且未收到有效数据包,则轮询过程使用虚拟元组调用时钟过滤器算法,就像元组已从网络到达一样。如果这种情况持续八次轮询间隔,寄存器将返回初始状态。

In the next step, the shift register stages are copied to a temporary list and the list sorted by increasing delta. Let i index the stages starting with the lowest delta. If the first tuple epoch t_0 is not later than the last valid sample epoch tp, the routine exits without affecting the current peer variables. Otherwise, let epsilon_i be the dispersion of the ith entry, then

在下一步中,移位寄存器级被复制到临时列表中,该列表按增量排序。让我从最低的增量开始索引阶段。如果第一个元组历元t_0不晚于最后一个有效样本历元tp,则例程退出,而不影响当前对等变量。否则,让epsilon_i是第i个条目的离散度,然后

                     i=n-1
                     ---     epsilon_i
      epsilon =       \     ----------
                      /        (i+1)
                     ---     2
                     i=0
        
                     i=n-1
                     ---     epsilon_i
      epsilon =       \     ----------
                      /        (i+1)
                     ---     2
                     i=0
        

is the peer dispersion p.disp. Note the overload of epsilon, whether input to the clock filter or output, the meaning should be clear from context.

是对等分散点p.disp。注意epsilon的过载,无论是输入到时钟滤波器还是输出,其含义都应该从上下文中明确。

The observer should note (a) if all stages contain the dummy tuple with dispersion MAXDISP, the computed dispersion is a little less than 16 s, (b) each time a valid tuple is shifted into the register, the dispersion drops by a little less than half, depending on the valid tuples dispersion, and (c) after the fourth valid packet the dispersion is usually a little less than 1 s, which is the assumed value of the MAXDIST parameter used by the selection algorithm to determine whether or not the peer variables are acceptable.

观察者应注意(a)如果所有级都包含离散度为MAXDISP的伪元组,则计算的离散度略小于16 s,(b)每次有效元组移位到寄存器时,离散度下降略小于一半,具体取决于有效元组的离散度,以及(c)在第四个有效数据包之后,离散度通常略小于1s,这是选择算法用于确定对等变量是否可接受的MAXDIST参数的假定值。

Let the first stage offset in the sorted list be theta_0; then, for the other stages in any order, the jitter is the RMS average

让排序列表中的第一级偏移量为θ0;然后,对于任何顺序的其他阶段,抖动是RMS平均值

                          +-----                 -----+^1/2
                          |  n-1                      |
                          |  ---                      |
                  1       |  \                     2  |
      psi   =  -------- * |  /    (theta_0-theta_j)   |
                (n-1)     |  ---                      |
                          |  j=1                      |
                          +-----                 -----+
        
                          +-----                 -----+^1/2
                          |  n-1                      |
                          |  ---                      |
                  1       |  \                     2  |
      psi   =  -------- * |  /    (theta_0-theta_j)   |
                (n-1)     |  ---                      |
                          |  j=1                      |
                          +-----                 -----+
        

where n is the number of valid tuples in the filter (n > 1). In order to ensure consistency and avoid divide exceptions in other

其中n是过滤器中的有效元组数(n>1)。为了确保一致性并避免在其他

computations, the psi is bounded from below by the system precision s.rho expressed in seconds. While not in general considered a major factor in ranking server quality, jitter is a valuable indicator of fundamental timekeeping performance and network congestion state. Of particular importance to the mitigation algorithms is the peer synchronization distance, which is computed from the delay and dispersion.

计算时,psi由系统精度s.rho(以秒为单位)从下方限定。虽然一般不认为抖动是服务器质量排名的主要因素,但抖动是基本计时性能和网络拥塞状态的一个有价值的指标。对缓解算法特别重要的是对等同步距离,它是根据延迟和色散计算的。

   lambda = (delta / 2) + epsilon.
        
   lambda = (delta / 2) + epsilon.
        

Note that epsilon and therefore lambda increase at rate PHI. The lambda is not a state variable, since lambda is recalculated at each use. It is a component of the root synchronization distance used by the mitigation algorithms as a metric to evaluate the quality of time available from each server.

注意,ε和λ以φ的速率增加。lambda不是状态变量,因为lambda在每次使用时都会重新计算。它是根同步距离的一个组成部分,缓解算法将其用作评估每个服务器可用时间质量的指标。

It is important to note that, unlike NTPv3, NTPv4 associations do not show a timeout condition by setting the stratum to 16 and leap indicator to 3. The association variables retain the values determined upon arrival of the last packet. In NTPv4, lambda increases with time, so eventually the synchronization distance exceeds the distance threshold MAXDIST, in which case the association is considered unfit for synchronization.

需要注意的是,与NTPv3不同,NTPv4关联不会通过将地层设置为16并将leap指示符设置为3来显示超时条件。关联变量保留最后一个数据包到达时确定的值。在NTPv4中,lambda随时间增加,因此最终同步距离超过距离阈值MAXDIST,在这种情况下,关联被认为不适合同步。

An example implementation of the clock filter algorithm is shown in the clock_filter() routine of Appendix A.5.2.

附录A.5.2的clock_filter()例程中显示了时钟滤波器算法的示例实现。

11. System Process
11. 系统过程

As each new sample (theta, delta, epsilon, jitter, t) is produced by the clock filter algorithm, all peer processes are scanned by the mitigation algorithms consisting of the selection, cluster, combine, and clock discipline algorithms in the system process. The selection algorithm scans all associations and casts off the falsetickers, which have demonstrably incorrect time, leaving the truechimers as result. In a series of rounds, the cluster algorithm discards the association statistically furthest from the centroid until a specified minimum number of survivors remain. The combine algorithm produces the best and final statistics on a weighted average basis. The final offset is passed to the clock discipline algorithm to steer the system clock to the correct time.

由于每个新样本(θ、δ、ε、抖动、t)都是由时钟滤波器算法产生的,因此所有对等进程都由缓解算法扫描,缓解算法包括系统进程中的选择、聚类、组合和时钟规程算法。选择算法会扫描所有关联,并去掉时间明显不正确的Falsticker,结果留下TrueChimer。在一系列轮次中,聚类算法丢弃统计上距离质心最远的关联,直到保留指定的最小幸存者数。联合算法在加权平均的基础上产生最佳和最终统计数据。最后的偏移量传递给时钟规程算法,以将系统时钟调整到正确的时间。

The cluster algorithm selects one of the survivors as the system peer. The associated statistics (theta, delta, epsilon, jitter, t) are used to construct the system variables inherited by dependent servers and clients and made available to other applications running on the same machine.

集群算法选择一个幸存者作为系统对等方。相关的统计信息(θ、δ、ε、抖动、t)用于构造由从属服务器和客户端继承的系统变量,并可用于在同一台机器上运行的其他应用程序。

11.1. System Process Variables
11.1. 系统过程变量

Figure 23 summarizes the common names, formula names, and a short description of each system variable. Unless noted otherwise, all variables have assumed prefix s.

图23总结了常见名称、公式名称和每个系统变量的简短描述。除非另有说明,否则所有变量均采用前缀s。

                +-----------+------------+------------------------+
                | Name      | Formula    | Description            |
                +-----------+------------+------------------------+
                | t         | t          | update time            |
                | p         | p          | system peer identifier |
                | leap      | leap       | leap indicator         |
                | stratum   | stratum    | stratum                |
                | precision | rho        | precision              |
                | offset    | THETA      | combined offset        |
                | jitter    | PSI        | combined jitter        |
                | rootdelay | DELTA      | root delay             |
                | rootdisp  | EPSILON    | root dispersion        |
                | v         | v          | survivor list          |
                | refid     | refid      | reference ID           |
                | reftime   | reftime    | reference time         |
                | NMIN      | 3          | minimum survivors      |
                | CMIN      | 1          | minimum candidates     |
                +-----------+------------+------------------------+
        
                +-----------+------------+------------------------+
                | Name      | Formula    | Description            |
                +-----------+------------+------------------------+
                | t         | t          | update time            |
                | p         | p          | system peer identifier |
                | leap      | leap       | leap indicator         |
                | stratum   | stratum    | stratum                |
                | precision | rho        | precision              |
                | offset    | THETA      | combined offset        |
                | jitter    | PSI        | combined jitter        |
                | rootdelay | DELTA      | root delay             |
                | rootdisp  | EPSILON    | root dispersion        |
                | v         | v          | survivor list          |
                | refid     | refid      | reference ID           |
                | reftime   | reftime    | reference time         |
                | NMIN      | 3          | minimum survivors      |
                | CMIN      | 1          | minimum candidates     |
                +-----------+------------+------------------------+
        

Figure 23: System Process Variables

图23:系统过程变量

Except for the t, p, offset, and jitter variables and the NMIN and CMIN constants, the variables have the same format and interpretation as the peer variables of the same name. The NMIN and CMIN parameters are used by the selection and cluster algorithms described in the next section.

除了t、p、offset和jitter变量以及NMIN和CMIN常量外,这些变量与同名的对等变量具有相同的格式和解释。NMIN和CMIN参数由下一节描述的选择和聚类算法使用。

The t variable is the seconds counter at the time of the last update. An example is shown by the clock_update() routine in Appendix A.5.5.4. The p variable is the system peer identifier determined by the cluster() routine in Section 11.2.2. The precision variable has the same format as the packet variable of the same name. The precision is defined as the larger of the resolution and time to read the clock, in log2 units. For instance, the precision of a mains-frequency clock incrementing at 60 Hz is 16 ms, even when the system clock hardware representation is to the nanosecond.

t变量是上次更新时的秒数计数器。附录A.5.5.4中的时钟更新()例程显示了一个示例。p变量是由第11.2.2节中的cluster()例程确定的系统对等标识符。精度变量的格式与同名的数据包变量的格式相同。精度定义为分辨率和读取时钟时间中的较大值,以log2为单位。例如,即使系统时钟硬件表示为纳秒,以60 Hz递增的电源频率时钟的精度也为16 ms。

The offset and jitter variables are determined by the combine algorithm in Section 11.2.3. These values represent the best and final offset and jitter used to discipline the system clock.

偏移和抖动变量由第11.2.3节中的联合算法确定。这些值表示用于调节系统时钟的最佳和最终偏移和抖动。

Initially, all variables are cleared to zero, then the leap is set to 3 (unsynchronized) and stratum is set to MAXSTRAT (16). Remember that MAXSTRAT is mapped to zero in the transmitted packet.

最初,所有变量都被清除为零,然后闰被设置为3(未同步),地层被设置为MAXSTRAT(16)。请记住,MAXSTRAT在传输的数据包中映射为零。

11.2. System Process Operations
11.2. 系统进程操作

Figure 24 summarizes the system process operations performed by the clock select routine. The selection algorithm described in Section 11.2.1 produces a majority clique of presumed correct candidates (truechimers) based on agreement principles. The cluster algorithm described in Section 11.2.2 discards outliers to produce the most accurate survivors. The combine algorithm described in Section 11.2.3 provides the best and final offset for the clock discipline algorithm. An example is described in Appendix A.5.5.6. If the selection algorithm cannot produce a majority clique, or if it cannot produce at least CMIN survivors, the system process exits without disciplining the system clock. If successful, the cluster algorithm selects the statistically best candidate as the system peer and its variables are inherited as the system variables.

图24总结了时钟选择例程执行的系统进程操作。第11.2.1节中所述的选择算法根据一致性原则产生假定正确候选人(TrueChimer)的多数群体。第11.2.2节中描述的聚类算法丢弃异常值,以产生最准确的幸存者。第11.2.3节中描述的联合算法为时钟规程算法提供了最佳和最终偏移。附录A.5.5.6中描述了一个示例。如果选择算法不能产生多数派,或者如果它至少不能产生CMIN幸存者,则系统进程将退出,而不调整系统时钟。如果成功,集群算法将选择统计上最好的候选对象作为系统对等对象,并将其变量作为系统变量继承。

                          +-----------------+
                          | clock_select()  |
                          +-----------------+
   ................................|...........
   .                               V          .
   .      yes +---------+ +-----------------+ .
   .       +--| accept? | | scan candidates | .
   .       |  +---------+ |                 | .
   .       V        no |  |                 | .
   .  +---------+      |  |                 | .
   .  | add peer|      |  |                 | .
   .  +----------      |  |                 | .
   .       |           V  |                 | .
   .       +---------->-->|                 | .
   .                      |                 | .
   . Selection Algorithm  +-----------------+ .
   .................................|..........
                                    V
                       no +-------------------+
            +-------------|     survivors?    |
            |             +-------------------+
            |                       | yes
            |                       V
            |             +-------------------+
            |             | Cluster Algorithm |
            |             +-------------------+
            |                       |
            |                       V
            V         yes +-------------------+
            |<------------|     n < CMIN?     |
            |             +-------------------+
            V                       |
     +-----------------+            V no
     |   s.p = NULL    |  +-------------------+
     +-----------------+  |   s.p = v_0.p     |
            |             +-------------------+
            V                       |
     +-----------------+            V
     | return (UNSYNC) |  +-------------------+
     +-----------------+  |   return (SYNC)   |
                          +-------------------+
        
                          +-----------------+
                          | clock_select()  |
                          +-----------------+
   ................................|...........
   .                               V          .
   .      yes +---------+ +-----------------+ .
   .       +--| accept? | | scan candidates | .
   .       |  +---------+ |                 | .
   .       V        no |  |                 | .
   .  +---------+      |  |                 | .
   .  | add peer|      |  |                 | .
   .  +----------      |  |                 | .
   .       |           V  |                 | .
   .       +---------->-->|                 | .
   .                      |                 | .
   . Selection Algorithm  +-----------------+ .
   .................................|..........
                                    V
                       no +-------------------+
            +-------------|     survivors?    |
            |             +-------------------+
            |                       | yes
            |                       V
            |             +-------------------+
            |             | Cluster Algorithm |
            |             +-------------------+
            |                       |
            |                       V
            V         yes +-------------------+
            |<------------|     n < CMIN?     |
            |             +-------------------+
            V                       |
     +-----------------+            V no
     |   s.p = NULL    |  +-------------------+
     +-----------------+  |   s.p = v_0.p     |
            |             +-------------------+
            V                       |
     +-----------------+            V
     | return (UNSYNC) |  +-------------------+
     +-----------------+  |   return (SYNC)   |
                          +-------------------+
        

Figure 24: Clock Select Routine

图24:时钟选择程序

11.2.1. Selection Algorithm
11.2.1. 选择算法

Note that the selection and cluster algorithms are described separately, but combined in the code skeleton. The selection algorithm operates to find an intersection interval containing a majority clique of truechimers using Byzantine agreement principles originally proposed by Marzullo [ref6], but modified to improve accuracy. An overview of the algorithm is given below and described in the first half of the clock_select() routine in Appendix A.5.5.1.

请注意,选择和集群算法是单独描述的,但在代码框架中结合使用。选择算法使用拜占庭协议原则(最初由Marzullo提出,参考文献6),但经过修改以提高精度,用于查找包含大多数TrueChemer群体的相交区间。下面给出了该算法的概述,并在附录A.5.5.1中的clock_select()例程的前半部分进行了描述。

First, those servers that are unusable according to the rules of the protocol are detected and discarded as shown by the accept() routine in Appendix A.5.5.3. Next, a set of tuples (p, type, edge) is generated for the remaining candidates. Here, p is the association identifier and type identifies the upper (+1), middle (0), and lower (-1) endpoints of a correctness interval centered on theta for that candidate. This results in three tuples, lowpoint (p, -1, theta - lambda), midpoint (p, 0, theta), and highpoint (p, +1, theta + lambda), where lambda is the root synchronization distance. An example of this calculation is shown by the rootdist() routine in Appendix A.5.1.1. The steps of the algorithm are:

首先,如附录A.5.5.3中的accept()例程所示,检测并丢弃根据协议规则不可用的服务器。接下来,为其余候选对象生成一组元组(p、type、edge)。这里,p是关联标识符,type标识以该候选者的θ为中心的正确性间隔的上(+1)、中(0)和下(-1)端点。这将产生三个元组:低点(p,-1,θ-lambda)、中点(p,0,θ)和高点(p,+1,θ+lambda),其中lambda是根同步距离。附录A.5.1.1中的rootdist()例程显示了此计算的示例。该算法的步骤如下:

1. For each of m associations, place three tuples as defined above on the candidate list.

1. 对于m个关联中的每一个,将三个元组(如上所述)放在候选列表上。

2. Sort the tuples on the list by the edge component. Order the lowpoint, midpoint, and highpoint of these intervals from lowest to highest. Set the number of falsetickers f = 0.

2. 按边缘组件对列表上的元组进行排序。从最低到最高排列这些区间的低点、中点和高点。设置错误标记的数量f=0。

3. Set the number of midpoints d = 0. Set c = 0. Scan from lowest endpoint to highest. Add one to c for every lowpoint, subtract one for every highpoint, add one to d for every midpoint. If c >= m - f, stop; set l = current lowpoint.

3. 设置中点的数量d=0。设置c=0。从最低端点扫描到最高端点。每个低点加一到c,每个高点减一,每个中点加一到d。如果c>=m-f,则停止;设置l=当前低点。

4. Set c = 0. Scan from highest endpoint to lowest. Add one to c for every highpoint, subtract one for every lowpoint, add one to d for every midpoint. If c >= m - f, stop; set u = current highpoint.

4. 设置c=0。从最高端点扫描到最低端点。每个高点加一到c,每个低点减一,每个中点加一到d。如果c>=m-f,则停止;设置u=当前高点。

5. Is d = f and l < u? If yes, then follow step 5A; else, follow step 5B.

5. d=f,l<u吗?如果是,则执行步骤5A;否则,请执行步骤5B。

5A. Success: the intersection interval is [l, u].

5A。成功:相交间隔为[l,u]。

5B. Add one to f. Is f < (m / 2)? If yes, then go to step 3 again. If no, then go to step 6.

5B。将一个添加到f。f是否小于(m/2)?如果是,则再次转至步骤3。如果否,则转至步骤6。

6. Failure; a majority clique could not be found. There are no suitable candidates to discipline the system clock.

6. 失败找不到多数派。没有合适的候选人来管理系统时钟。

The algorithm is described in detail in Appendix A.5.5.1. Note that it starts with the assumption that there are no falsetickers (f = 0) and attempts to find a non-empty intersection interval containing the midpoints of all correct servers, i.e., truechimers. If a non-empty interval cannot be found, it increases the number of assumed falsetickers by one and tries again. If a non-empty interval is found and the number of falsetickers is less than the number of truechimers, a majority clique has been found and the midpoint of each truechimer (theta) represents the candidates available to the cluster algorithm.

附录A.5.5.1中详细描述了该算法。请注意,它首先假设不存在错误提示(f=0),并尝试查找包含所有正确服务器(即TrueChimer)中点的非空交叉点间隔。如果找不到非空间隔,则会将假定的FalseTicker数增加1,然后重试。如果发现一个非空的间隔,并且Falsticker的数量小于truechimer的数量,则发现了一个多数群体,并且每个truechimer的中点(θ)表示聚类算法可用的候选对象。

If a majority clique is not found, or if the number of truechimers is less than CMIN, there are insufficient candidates to discipline the system clock. CMIN defines the minimum number of servers consistent with the correctness requirements. Suspicious operators would set CMIN to ensure multiple redundant servers are available for the algorithms to mitigate properly. However, for historic reasons the default value for CMIN is one.

如果没有找到多数派,或者如果TrueChimer的数量少于CMIN,则没有足够的候选人来约束系统时钟。CMIN定义了符合正确性要求的最小服务器数量。可疑运营商将设置CMIN,以确保有多个冗余服务器可供算法适当缓解。但是,出于历史原因,CMIN的默认值为1。

11.2.2. Cluster Algorithm
11.2.2. 聚类算法

The candidates of the majority clique are placed on the survivor list v in the form of tuples (p, theta_p, psi_p, lambda_p), where p is an association identifier, theta_p, psi_p, and stratum_p the current offset, jitter and stratum of association p, respectively, and lambda_p is a merit factor equal to stratum_p * MAXDIST + lambda, where lambda is the root synchronization distance for association p. The list is processed by the cluster algorithm below. An example is shown by the second half of the clock_select() algorithm in Appendix A.5.5.1.

多数派的候选人以元组(p,θp,psi p,lambda p)的形式被放置在幸存者列表v上,其中p是关联标识符,θp,psi p和层p分别是当前偏移量、抖动和关联层p,lambda p是等于层p*MAXDIST+lambda的优点因子,其中lambda是关联p的根同步距离。列表由下面的集群算法处理。附录A.5.5.1中的clock_select()算法的后半部分显示了一个示例。

1. Let (p, theta_p, psi_p, lambda_p) represent a survivor candidate.

1. 让(p,θp,psi p,lambda p)代表一个幸存者候选者。

2. Sort the candidates by increasing lambda_p. Let n be the number of candidates and NMIN the minimum required number of survivors.

2. 通过增加lambda_p对候选对象进行排序。设n为候选数,NMIN为所需的最小幸存者数。

3. For each candidate, compute the selection jitter psi_s:

3. 对于每个候选对象,计算选择抖动psis:

             +-----                       -----+^1/2
             |        n-1                      |
             |        ---                      |
             |   1    \                     2  |
     psi_s = | ---- * /  (theta_s - theta_j)   |
             |  n-1   ---                      |
             |        j=1                      |
             +-----                       -----+
        
             +-----                       -----+^1/2
             |        n-1                      |
             |        ---                      |
             |   1    \                     2  |
     psi_s = | ---- * /  (theta_s - theta_j)   |
             |  n-1   ---                      |
             |        j=1                      |
             +-----                       -----+
        

4. Select psi_max as the candidate with maximum psi_s.

4. 选择psi_max作为具有最大psi_s的候选。

5. Select psi_min as the candidate with minimum psi_p.

5. 选择psi_min作为最小psi_p的候选。

6. Is psi_max < psi_min or n <= NMIN? If yes, follow step 6A; otherwise, follow step 6B.

6. psi_最大值是否小于psi_最小值或n是否小于等于n分钟?如果是,则执行步骤6A;否则,遵循步骤6B。

6A. Done. The remaining candidates on the survivor list are ranked in the order of preference. The first entry on the list represents the system peer; its variables are used later to update the system variables.

6A。完成。幸存者名单上的其余候选人按优先顺序排列。列表上的第一个条目表示系统对等点;其变量稍后用于更新系统变量。

6B. Delete the outlier candidate with psi_max; reduce n by one and go back to step 3.

6B。用psi_max删除异常候选值;将n减少1,然后返回步骤3。

The algorithm operates in a series of rounds where each round discards the statistical outlier with maximum selection jitter psi_s. However, if psi_s is less than the minimum peer jitter psi_p, no improvement is possible by discarding outliers. This and the minimum number of survivors represent the terminating conditions of the algorithm. Upon termination, the final value of psi_max is saved as the system selection jitter PSI_s for use later.

该算法在一系列轮中运行,每轮丢弃具有最大选择抖动psis的统计异常值。但是,如果psi_s小于最小对等抖动psi_p,则不可能通过丢弃异常值来改善。这和幸存者的最小数量表示算法的终止条件。终止后,psi_max的最终值将保存为系统选择抖动psi_s,以供以后使用。

11.2.3. Combine Algorithm
11.2.3. 组合算法

The clock combine route processes the remaining survivors to produce the best and final data for the clock discipline algorithm. The routine processes peer offset and jitter statistics to produce the combined system offset THETA and system peer jitter PSI_p, where each server statistic is weighted by the reciprocal of the root synchronization distance and the result normalized. An example is shown by the clock_combine() routine in Appendix A.5.5.5

时钟组合路由处理剩余的幸存者,为时钟规程算法生成最佳和最终数据。该例程处理对等偏移和抖动统计信息,以生成组合的系统偏移θ和系统对等抖动PSI_p,其中每个服务器统计信息由根同步距离的倒数和归一化结果加权。附录A.5.5.5中的clock_combine()例程显示了一个示例

The combined THETA is passed to the clock update routine. The first candidate on the survivor list is nominated as the system peer with identifier p. The system peer jitter PSI_p is a component of the system jitter PSI. It is used along with the selection jitter PSI_s to produce the system jitter:

组合θ被传递到时钟更新例程。幸存者列表上的第一个候选人被指定为标识符为p的系统对等方。系统对等抖动PSI_p是系统抖动PSI的一个组件。它与选择抖动PSI_一起用于产生系统抖动:

   PSI = [(PSI_s)^2 + (PSI_p)^2]^1/2
        
   PSI = [(PSI_s)^2 + (PSI_p)^2]^1/2
        

Each time an update is received from the system peer, the clock update routine is called. By rule, an update is discarded if its time of arrival p.t is not strictly later than the last update used s.t. The labels IGNOR, PANIC, ADJ, and STEP refer to return codes from the local clock routine described in the next section.

每次从系统对等方接收到更新时,都会调用时钟更新例程。根据规则,如果更新的到达时间p.t不严格晚于上次使用的更新s.t,则会丢弃更新。标签IGNOR、PANIC、ADJ和STEP是指下一节中描述的本地时钟例程的返回代码。

IGNORE means the update has been ignored as an outlier. PANIC means the offset is greater than the panic threshold PANICT (1000 s) and SHOULD cause the program to exit with a diagnostic message to the

忽略表示更新已作为异常值被忽略。“紧急”表示偏移量大于紧急阈值“紧急”(1000秒),应导致程序退出,并向程序发送诊断消息

system log. STEP means the offset is less than the panic threshold, but greater than the step threshold STEPT (125 ms). In this case, the clock is stepped to the correct offset, but since this means all peer data have been invalidated, all associations MUST be reset and the client begins as at initial start.

系统日志。阶跃表示偏移量小于紧急阈值,但大于阶跃阈值STEPT(125毫秒)。在这种情况下,时钟步进到正确的偏移量,但由于这意味着所有对等数据都已无效,因此必须重置所有关联,并且客户端从初始启动时开始。

ADJ means the offset is less than the step threshold and thus a valid update. In this case, the system variables are updated from the peer variables as shown in Figure 25.

ADJ表示偏移量小于阶跃阈值,因此是有效的更新。在这种情况下,系统变量从对等变量更新,如图25所示。

                  +-------------------------------------------+
                  | System Variable <-- System Peer Variable  |        |
                  +-------------------------------------------+
                  | s.leap      <-- p.leap                    |
                  | s.stratum   <-- p.stratum + 1             |
                  | s.offset    <-- THETA                     |
                  | s.jitter    <-- PSI                       |
                  | s.rootdelay <-- p.delta_r + delta         |
                  | s.rootdisp  <-- p.epsilon_r + p.epsilon + |
                  |                 p.psi + PHI * (s.t - p.t) |
                  |                 + |THETA|                 |
                  | s.refid     <-- p.refid                   |
                  | s.reftime   <-- p.reftime                 |
                  | s.t         <-- p.t                       |
                  +-------------------------------------------+
        
                  +-------------------------------------------+
                  | System Variable <-- System Peer Variable  |        |
                  +-------------------------------------------+
                  | s.leap      <-- p.leap                    |
                  | s.stratum   <-- p.stratum + 1             |
                  | s.offset    <-- THETA                     |
                  | s.jitter    <-- PSI                       |
                  | s.rootdelay <-- p.delta_r + delta         |
                  | s.rootdisp  <-- p.epsilon_r + p.epsilon + |
                  |                 p.psi + PHI * (s.t - p.t) |
                  |                 + |THETA|                 |
                  | s.refid     <-- p.refid                   |
                  | s.reftime   <-- p.reftime                 |
                  | s.t         <-- p.t                       |
                  +-------------------------------------------+
        

Figure 25: System Variables Update

图25:系统变量更新

There is an important detail not shown. The dispersion increment (p.epsilon + p.psi + PHI * (s.t - p.t) + |THETA|) is bounded from below by MINDISP. In subnets with very fast processors and networks and very small delay and dispersion this forces a monotone-definite increase in s.rootdisp (EPSILON), which avoids loops between peers operating at the same stratum.

有一个重要的细节没有显示出来。色散增量(p.epsilon+p.psi+PHI*(s.t-p.t)+θ)由MINDISP从下方限定。在具有非常快的处理器和网络以及非常小的延迟和分散的子网中,这迫使s.rootdisp(EPSILON)单调确定地增加,从而避免了在同一层上运行的对等方之间的循环。

The system variables are available to dependent application programs as nominal performance statistics. The system offset THETA is the clock offset relative to the available synchronization sources. The system jitter PSI is an estimate of the error in determining this value, elsewhere called the expected error. The root delay DELTA is the total round-trip delay relative to the primary server. The root dispersion EPSILON is the dispersion accumulated over the network from the primary server. Finally, the root synchronization distance is defined as:

系统变量可作为标称性能统计信息提供给相关应用程序。系统偏移θ是相对于可用同步源的时钟偏移。系统抖动PSI是确定该值时的误差估计值,在别处称为预期误差。根延迟增量是相对于主服务器的总往返延迟。根色散ε是从主服务器通过网络累积的色散。最后,根同步距离定义为:

LAMBDA = EPSILON + DELTA / 2,

λ=ε+δ/2,

which represents the maximum error due all causes and is designated the root synchronization distance.

表示所有原因导致的最大错误,并指定为根同步距离。

An example of the clock update routine is provided in Appendix A.5.5.4.

附录A.5.5.4中提供了时钟更新程序的示例。

11.3. Clock Discipline Algorithm
11.3. 时钟纪律算法

The NTPv4 clock discipline algorithm, shortened to discipline in the following, functions as a combination of two quite philosophically different feedback control systems. In a phase-locked loop (PLL) design, periodic phase updates at update intervals mu seconds are used directly to minimize the time error and indirectly the frequency error. In a frequency-locked loop (FLL) design, periodic frequency updates at intervals mu are used directly to minimize the frequency error and indirectly the time error. As shown in [ref7], a PLL usually works better when network jitter dominates, while an FLL works better when oscillator wander dominates. This section contains an outline of how the NTPv4 design works. An in-depth discussion of the design principles is provided in [ref7], which also includes a performance analysis.

NTPv4时钟规程算法在下文中简称为规程,其功能是两个完全不同的反馈控制系统的组合。在锁相环(PLL)设计中,以μs为更新间隔的周期性相位更新直接用于最小化时间误差,间接用于最小化频率误差。在频率锁定环(FLL)设计中,以μ为间隔的周期性频率更新直接用于最小化频率误差,间接用于最小化时间误差。如参考文献7所示,当网络抖动占主导地位时,PLL通常工作得更好,而当振荡器漂移占主导地位时,FLL工作得更好。本节概述了NTPv4设计的工作原理。参考文献7对设计原则进行了深入讨论,其中还包括性能分析。

The discipline is implemented as the feedback control system shown in Figure 26. The variable theta_r represents the combine algorithm offset (reference phase) and theta_c the VFO offset (control phase). Each update produces a signal V_d representing the instantaneous phase difference theta_r - theta_c. The clock filter for each server functions as a tapped delay line, with the output taken at the tap selected by the clock filter algorithm. The selection, cluster, and combine algorithms combine the data from multiple filters to produce the signal V_s. The loop filter, with impulse response F(t), produces the signal V_c, which controls the VFO frequency omega_c and thus the integral of the phase theta_c which closes the loop. The V_c signal is generated by the clock-adjust process in Section 12. The detailed equations that implement these functions are best presented in the routines of Appendices A.5.5.6 and A.5.6.1.

该规程作为反馈控制系统实施,如图26所示。变量θu r表示联合算法偏移量(参考相位),θc表示VFO偏移量(控制相位)。每次更新产生一个表示瞬时相位差θr-θc的信号V_d。每个服务器的时钟滤波器作为抽头延迟线工作,其输出在由时钟滤波器算法选择的抽头处。选择、聚类和组合算法组合来自多个滤波器的数据,以产生信号V_。具有脉冲响应F(t)的环路滤波器产生信号V_c,该信号控制VFO频率ω_c,从而控制关闭环路的相位θ_c的积分。V_c信号由部分12中的时钟调整过程生成。附录A.5.5.6和A.5.6.1的例行程序中最好地介绍了实现这些功能的详细方程式。

                theta_r + +---------\        +----------------+
            NTP --------->|  Phase   \  V_d  |                | V_s
                theta_c - | Detector  ------>|  Clock Filter  |----+
                +-------->|          /       |                |    |
                |         +---------/        +----------------+    |
                |                                                  |
              -----                                                |
             /     \                                               |
             | VFO |                                               |
             \     /                                               |
              -----    .......................................     |
                ^      .            Loop Filter              .     |
                |      . +---------+   x  +-------------+    .     |
                | V_c  . |         |<-----|             |    .     |
                +------.-|  Clock  |   y  | Phase/Freq  |<---------+
                       . | Adjust  |<-----| Prediction  |    .
                       . |         |      |             |    .
                       . +---------+      +-------------+    .
                       .......................................
        
                theta_r + +---------\        +----------------+
            NTP --------->|  Phase   \  V_d  |                | V_s
                theta_c - | Detector  ------>|  Clock Filter  |----+
                +-------->|          /       |                |    |
                |         +---------/        +----------------+    |
                |                                                  |
              -----                                                |
             /     \                                               |
             | VFO |                                               |
             \     /                                               |
              -----    .......................................     |
                ^      .            Loop Filter              .     |
                |      . +---------+   x  +-------------+    .     |
                | V_c  . |         |<-----|             |    .     |
                +------.-|  Clock  |   y  | Phase/Freq  |<---------+
                       . | Adjust  |<-----| Prediction  |    .
                       . |         |      |             |    .
                       . +---------+      +-------------+    .
                       .......................................
        

Figure 26: Clock Discipline Feedback Loop

图26:时钟规程反馈回路

Ordinarily, the pseudo-linear feedback loop described above operates to discipline the system clock. However, there are cases where a non-linear algorithm offers considerable improvement. One case is when the discipline starts without knowledge of the intrinsic clock frequency. The pseudo-linear loop takes several hours to develop an accurate measurement and during most of that time the poll interval cannot be increased. The non-linear loop described below does this in 15 minutes. Another case is when occasional bursts of large jitter are present due to congested network links. The state machine described below resists error bursts lasting less than 15 minutes.

通常,上述伪线性反馈回路用于调节系统时钟。然而,在某些情况下,非线性算法提供了相当大的改进。一种情况是,学科开始时不知道固有时钟频率。伪线性循环需要几个小时才能形成精确的测量,在大部分时间内,轮询间隔无法增加。下面描述的非线性循环在15分钟内完成。另一种情况是,由于网络链路拥塞,偶尔会出现大抖动。下面描述的状态机可以抵抗持续时间少于15分钟的错误突发。

Figure 27 contains a summary of the variables and parameters including the variable (lowercase) or parameter (uppercase) name, formula name, and short description. Unless noted otherwise, all variables have assumed prefix c. The variables t, tc, state, hyster, and count are integers; the remaining variables are floating doubles. The function of each will be explained in the algorithm descriptions below.

图27包含变量和参数的摘要,包括变量(小写)或参数(大写)名称、公式名称和简短描述。除非另有说明,所有变量均采用前缀c。变量t、tc、state、歇斯底里和count是整数;剩下的变量是浮动双精度。下面的算法描述将解释每种算法的功能。

                +--------+------------+--------------------------+
                | Name   | Formula    | Description              |
                +--------+------------+--------------------------+
                | t      | timer      | seconds counter          |
                | offset | theta      | combined offset          |
                | resid  | theta_r    | residual offset          |
                | freq   | phi        | clock frequency          |
                | jitter | psi        | clock offset jitter      |
                | wander | omega      | clock frequency wander   |
                | tc     | tau        | time constant (log2)     |
                | state  | state      | state                    |
                | adj    | adj        | frequency adjustment     |
                | hyster | hyster     | hysteresis counter       |
                | STEPT  | 125        | step threshold (.125 s)  |
                | WATCH  | 900        | stepout thresh(s)        |
                | PANICT | 1000       | panic threshold (1000 s) |
                | LIMIT  | 30         | hysteresis limit         |
                | PGATE  | 4          | hysteresis gate          |
                | TC     | 16         | time constant scale      |
                | AVG    | 8          | averaging constant       |
                +--------+------------+--------------------------+
        
                +--------+------------+--------------------------+
                | Name   | Formula    | Description              |
                +--------+------------+--------------------------+
                | t      | timer      | seconds counter          |
                | offset | theta      | combined offset          |
                | resid  | theta_r    | residual offset          |
                | freq   | phi        | clock frequency          |
                | jitter | psi        | clock offset jitter      |
                | wander | omega      | clock frequency wander   |
                | tc     | tau        | time constant (log2)     |
                | state  | state      | state                    |
                | adj    | adj        | frequency adjustment     |
                | hyster | hyster     | hysteresis counter       |
                | STEPT  | 125        | step threshold (.125 s)  |
                | WATCH  | 900        | stepout thresh(s)        |
                | PANICT | 1000       | panic threshold (1000 s) |
                | LIMIT  | 30         | hysteresis limit         |
                | PGATE  | 4          | hysteresis gate          |
                | TC     | 16         | time constant scale      |
                | AVG    | 8          | averaging constant       |
                +--------+------------+--------------------------+
        

Figure 27: Clock Discipline Variables and Parameters

图27:时钟规程变量和参数

The process terminates immediately if the offset is greater than the panic threshold PANICT (1000 s). The state transition function is described by the rstclock() function in Appendix A.5.5.7. Figure 28 shows the state transition function used by this routine. It has four columns showing, respectively, the state name, predicate and action if the offset theta is less than the step threshold, the predicate and actions otherwise, and finally some comments.

如果偏移量大于紧急阈值(1000秒),则进程立即终止。状态转换函数由附录A.5.5.7中的rstclock()函数描述。图28显示了该例程使用的状态转换函数。它有四列,分别显示状态名称、谓词和操作(如果偏移量θ小于步长阈值)、谓词和操作(否则),以及最后一些注释。

      +-------+---------------------+-------------------+--------------+
      | State | theta < STEP        | theta > STEP      | Comments     |
      +-------+---------------------+-------------------+--------------+
      | NSET  | ->FREQ              | ->FREQ            | no frequency |
      |       | adjust time         | step time         | file         |
      +-------+---------------------+-------------------+--------------+
      | FSET  | ->SYNC              | ->SYNC            | frequency    |
      |       | adjust time         | step time         | file         |
      +-------+---------------------+-------------------+--------------+
      | SPIK  | ->SYNC              | if < 900 s ->SPIK | outlier      |
      |       | adjust freq         | else ->SYNC       | detected     |
      |       | adjust time         | step freq         |              |
      |       |                     | step time         |              |
      +-------+---------------------+-------------------+--------------+
      | FREQ  | if < 900 s ->FREQ   | if < 900 s ->FREQ | initial      |
      |       | else ->SYNC         | else ->SYNC       | frequency    |
      |       | step freq           | step freq         |              |
      |       | adjust time         | adjust time       |              |
      +-------+---------------------+-------------------+--------------+
      | SYNC  | ->SYNC              | if < 900 s ->SPIK | normal       |
      |       | adjust freq         | else ->SYNC       | operation    |
      |       | adjust time         | step freq         |              |
      |       |                     | step time         |              |
      +-------+---------------------+-------------------+--------------+
        
      +-------+---------------------+-------------------+--------------+
      | State | theta < STEP        | theta > STEP      | Comments     |
      +-------+---------------------+-------------------+--------------+
      | NSET  | ->FREQ              | ->FREQ            | no frequency |
      |       | adjust time         | step time         | file         |
      +-------+---------------------+-------------------+--------------+
      | FSET  | ->SYNC              | ->SYNC            | frequency    |
      |       | adjust time         | step time         | file         |
      +-------+---------------------+-------------------+--------------+
      | SPIK  | ->SYNC              | if < 900 s ->SPIK | outlier      |
      |       | adjust freq         | else ->SYNC       | detected     |
      |       | adjust time         | step freq         |              |
      |       |                     | step time         |              |
      +-------+---------------------+-------------------+--------------+
      | FREQ  | if < 900 s ->FREQ   | if < 900 s ->FREQ | initial      |
      |       | else ->SYNC         | else ->SYNC       | frequency    |
      |       | step freq           | step freq         |              |
      |       | adjust time         | adjust time       |              |
      +-------+---------------------+-------------------+--------------+
      | SYNC  | ->SYNC              | if < 900 s ->SPIK | normal       |
      |       | adjust freq         | else ->SYNC       | operation    |
      |       | adjust time         | step freq         |              |
      |       |                     | step time         |              |
      +-------+---------------------+-------------------+--------------+
        

Figure 28: State Transition Function

图28:状态转换函数

In the table entries, the next state is identified by the arrow -> with the actions listed below. Actions such as adjust time and adjust frequency are implemented by the PLL/FLL feedback loop in the local_clock() routine. A step clock action is implemented by setting the clock directly, but this is done only after the stepout threshold WATCH (900 s) when the offset is more than the step threshold STEPT (.125 s). This resists clock steps under conditions of extreme network congestion.

在表条目中,下一个状态由箭头->标识,操作如下所示。诸如调整时间和调整频率等操作由本地时钟()例程中的PLL/FLL反馈回路执行。步进时钟动作通过直接设置时钟来实现,但只有在偏移量大于步进阈值STEPT(.125 s)时,才在步出阈值观察(900 s)后执行。在极端网络拥塞的情况下,这可以抵抗时钟步进。

The jitter (psi) and wander (omega) statistics are computed using an exponential average with weight factor AVG. The time constant exponent (tau) is determined by comparing psi with the magnitude of the current offset theta. If the offset is greater than PGATE (4) times the clock jitter, the hysteresis counter hyster is reduced by two; otherwise, it is increased by one. If hyster increases to the upper limit LIMIT (30), tau is increased by one; if it decreases to the lower limit -LIMIT (-30), tau is decreased by one. Normally, tau hovers near MAXPOLL, but quickly decreases if a temperature spike causes a frequency surge.

抖动(psi)和漂移(omega)统计使用加权因子平均值的指数平均值进行计算。时间常数指数(tau)通过将psi与当前偏移量θ的大小进行比较来确定。如果偏移量大于PGATE(4)倍时钟抖动,则滞后计数器滞后将减小两倍;否则,它将增加1。如果滞后增加到上限(30),则tau增加1;如果它降低到下限-limit(-30),则tau减少1。通常情况下,tau在MAXPOLL附近盘旋,但如果温度峰值导致频率激增,tau会迅速降低。

12. Clock-Adjust Process
12. 时钟调整过程

The actual clock-adjust process runs at one-second intervals to add the frequency correction and a fixed percentage of the residual offset theta_r. The theta_r is, in effect, the exponential decay of the theta value produced by the loop filter at each update. The TC parameter scales the time constant to match the poll interval for convenience. Note that the dispersion EPSILON increases by PHI at each second.

实际时钟调整过程以1秒的间隔运行,以添加频率校正和剩余偏移θr的固定百分比。θr实际上是循环滤波器在每次更新时产生的θ值的指数衰减。为了方便起见,TC参数会缩放时间常数以匹配轮询间隔。注意,色散ε每秒钟增加φ。

The clock-adjust process includes a timer interrupt facility driving the seconds counter c.t. It begins at zero when the service starts and increments once each second. At each interrupt, the clock_adjust() routine is called to incorporate the clock discipline time and frequency adjustments, then the associations are scanned to determine if the seconds counter equals or exceeds the p.next state variable defined in the next section. If so, the poll process is called to send a packet and compute the next p.next value.

时钟调整过程包括一个定时器中断设施,用于驱动秒计数器c.t。当服务启动时,时钟从零开始,并每秒递增一次。在每次中断时,调用clock_adjust()例程以合并时钟规程时间和频率调整,然后扫描关联,以确定秒计数器是否等于或超过下一节中定义的p.next状态变量。如果是这样,则调用轮询过程来发送数据包并计算下一个p.next值。

An example of the clock-adjust process is shown by the clock_adjust() routine in Appendix A.5.6.1.

时钟调整过程的示例如附录A.5.6.1中的时钟调整()例程所示。

13. Poll Process
13. 投票过程

Each association supports a poll process that runs at regular intervals to construct and send packets in symmetric, client, and broadcast server associations. It runs continuously, whether or not servers are reachable in order to manage the clock filter and reach register.

每个关联都支持定期运行的轮询过程,以在对称、客户端和广播服务器关联中构造和发送数据包。无论服务器是否可访问,它都会连续运行,以便管理时钟过滤器和访问寄存器。

13.1. Poll Process Variables
13.1. 轮询过程变量

Figure 29 summarizes the common names, formula names, and a short description of the poll process variables (lowercase) and parameters (uppercase). Unless noted otherwise, all variables have assumed prefix p.

图29总结了常见名称、公式名称以及轮询过程变量(小写)和参数(大写)的简短描述。除非另有说明,否则所有变量均采用前缀p。

                   +---------+---------+--------------------+
                   | Name    | Formula | Description        |
                   +---------+---------+--------------------+
                   | hpoll   | hpoll   | host poll exponent |
                   | last    | last    | last poll time     |
                   | next    | next    | next poll time     |
                   | reach   | reach   | reach register     |
                   | unreach | unreach | unreach counter    |
                   | UNREACH | 24      | unreach limit      |
                   | BCOUNT  | 8       | burst count        |
                   | BURST   | flag    | burst enable       |
                   | IBURST  | flag    | iburst enable      |
                   +---------+---------+--------------------+
        
                   +---------+---------+--------------------+
                   | Name    | Formula | Description        |
                   +---------+---------+--------------------+
                   | hpoll   | hpoll   | host poll exponent |
                   | last    | last    | last poll time     |
                   | next    | next    | next poll time     |
                   | reach   | reach   | reach register     |
                   | unreach | unreach | unreach counter    |
                   | UNREACH | 24      | unreach limit      |
                   | BCOUNT  | 8       | burst count        |
                   | BURST   | flag    | burst enable       |
                   | IBURST  | flag    | iburst enable      |
                   +---------+---------+--------------------+
        

Figure 29: Poll Process Variables and Parameters

图29:轮询过程变量和参数

The poll process variables are allocated in the association data structure along with the peer process variables. The following is a detailed description of the variables. The parameters will be called out in the following text.

轮询过程变量与对等过程变量一起分配到关联数据结构中。以下是变量的详细说明。参数将在以下文本中调用。

hpoll: signed integer representing the poll exponent, in log2 seconds

hpoll:表示轮询指数的有符号整数,以log2秒为单位

last: integer representing the seconds counter when the most recent packet was sent

last:表示发送最近数据包时秒数计数器的整数

next: integer representing the seconds counter when the next packet is to be sent

next:表示发送下一个数据包时秒数计数器的整数

reach: 8-bit integer shift register shared by the peer and poll processes

reach:对等进程和轮询进程共享的8位整数移位寄存器

unreach: integer representing the number of seconds the server has been unreachable

unreach:整数,表示无法访问服务器的秒数

13.2. Poll Process Operations
13.2. 轮询进程操作

As described previously, once each second the clock-adjust process is called. This routine calls the poll routine for each association in turn. If the time for the next poll message is greater than the seconds counter, the routine returns immediately. Symmetric (modes 1, 2), client (mode 3), and broadcast server (mode 5) associations routinely send packets. A broadcast client (mode 6) association runs the routine to update the reach and unreach variables, but does not send packets. The poll process calls the transmit process to send a packet. If in a burst (burst > 0), nothing further is done except call the poll update routine to set the next poll interval.

如前所述,每秒调用一次时钟调整过程。此例程依次调用每个关联的轮询例程。如果下一个轮询消息的时间大于秒计数器,则例程立即返回。对称(模式1、2)、客户端(模式3)和广播服务器(模式5)关联通常发送数据包。广播客户端(模式6)关联运行例程以更新reach和UNRACH变量,但不发送数据包。轮询进程调用传输进程来发送数据包。如果处于突发(突发>0),则除了调用轮询更新例程以设置下一个轮询间隔外,不会执行任何其他操作。

If not in a burst, the reach variable is shifted left by one bit, with zero replacing the rightmost bit. If the server has not been heard for the last three poll intervals, the clock filter routine is called to increase the dispersion. An example is shown in Appendix A.5.7.3.

如果不是在突发中,reach变量左移一位,最右边的位替换为零。如果在最近三个轮询间隔内没有听到服务器的声音,则调用时钟过滤器例程以增加离散度。附录A.5.7.3中给出了一个示例。

If the BURST flag is lit and the server is reachable and a valid source of synchronization is available, the client sends a burst of BCOUNT (8) packets at each poll interval. The interval between packets in the burst is two seconds. This is useful to accurately measure jitter with long poll intervals. If the IBURST flag is lit and this is the first packet sent when the server has been unreachable, the client sends a burst. This is useful to quickly reduce the synchronization distance below the distance threshold and synchronize the clock.

如果BURST标志亮起且服务器可访问且有效的同步源可用,则客户端将在每个轮询间隔发送一个突发的BCOUNT(8)数据包。突发中数据包之间的间隔为两秒。这对于精确测量长轮询间隔的抖动非常有用。如果IBURST标志亮起,并且这是无法访问服务器时发送的第一个数据包,则客户端将发送突发。这有助于快速将同步距离降低到距离阈值以下并同步时钟。

If the P_MANY flag is lit in the p.flags word of the association, this is a manycast client association. Manycast client associations send client mode packets to designated multicast group addresses at MINPOLL intervals. The association starts out with a TTL of 1. If by the time of the next poll there are fewer than MINCLOCK servers have been mobilized, the ttl is increased by one. If the ttl reaches the limit TTLMAX, without finding MINCLOCK servers, the poll interval increases until reaching BEACON, when it starts over from the beginning.

如果关联的P.flags单词中的P_MANY标志点亮,则这是一个manycast客户端关联。许多组播客户端关联以最小轮询间隔将客户端模式数据包发送到指定的组播组地址。该关联以TTL为1开始。如果到下一次轮询时,已动员的服务器少于MINCLOCK,则ttl将增加一个。如果ttl达到限制TTLMAX,但未找到MINCLOCK服务器,则轮询间隔将增加,直到到达信标,此时它将从头开始。

The poll() routine includes a feature that backs off the poll interval if the server becomes unreachable. If reach is nonzero, the server is reachable and unreach is set to zero; otherwise, unreach is incremented by one for each poll to the maximum UNREACH. Thereafter for each poll hpoll is increased by one, which doubles the poll interval up to the maximum MAXPOLL determined by the poll_update() routine. When the server again becomes reachable, unreach is set to zero, hpoll is reset to the tc system variable, and operation resumes normally.

poll()例程包含一个功能,当服务器无法访问时,该功能将取消轮询间隔。如果reach为非零,则服务器是可访问的,且未访问设置为零;否则,对于每个轮询,unreach将增加1,以达到最大unreach。此后,对于每个轮询,hpoll增加一倍,使轮询间隔增加一倍,直至poll_update()例程确定的最大MAXPOLL。当服务器再次变得可访问时,Unrach设置为零,hpoll重置为tc系统变量,操作正常恢复。

A packet is sent by the transmit process. Some header values are copied from the peer variables left by a previous packet and others from the system variables. Figure 30 shows which values are copied to each header field. In those implementations, using floating double data types for root delay and root dispersion, these must be converted to NTP short format. All other fields are either copied intact from peer and system variables or struck as a timestamp from the system clock.

数据包由传输过程发送。一些头值是从前一个数据包留下的对等变量复制的,而另一些头值是从系统变量复制的。图30显示了将哪些值复制到每个标题字段。在这些实现中,对根延迟和根分散使用浮动双数据类型,必须将它们转换为NTP短格式。所有其他字段要么从对等变量和系统变量中完整复制,要么作为时间戳从系统时钟中删除。

                   +-----------------------------------+
                   | Packet Variable <--   Variable    |
                   +-----------------------------------+
                   | x.leap        <--     s.leap      |
                   | x.version     <--     s.version   |
                   | x.mode        <--     s.mode      |
                   | x.stratum     <--     s.stratum   |
                   | x.poll        <--     s.poll      |
                   | x.precision   <--     s.precision |
                   | x.rootdelay   <--     s.rootdelay |
                   | x.rootdisp    <--     s.rootdisp  |
                   | x.refid       <--     s.refid     |
                   | x.reftime     <--     s.reftime   |
                   | x.org         <--     p.xmt       |
                   | x.rec         <--     p.dst       |
                   | x.xmt         <--     clock       |
                   | x.keyid       <--     p.keyid     |
                   | x.digest      <--     md5 digest  |
                   +-----------------------------------+
        
                   +-----------------------------------+
                   | Packet Variable <--   Variable    |
                   +-----------------------------------+
                   | x.leap        <--     s.leap      |
                   | x.version     <--     s.version   |
                   | x.mode        <--     s.mode      |
                   | x.stratum     <--     s.stratum   |
                   | x.poll        <--     s.poll      |
                   | x.precision   <--     s.precision |
                   | x.rootdelay   <--     s.rootdelay |
                   | x.rootdisp    <--     s.rootdisp  |
                   | x.refid       <--     s.refid     |
                   | x.reftime     <--     s.reftime   |
                   | x.org         <--     p.xmt       |
                   | x.rec         <--     p.dst       |
                   | x.xmt         <--     clock       |
                   | x.keyid       <--     p.keyid     |
                   | x.digest      <--     md5 digest  |
                   +-----------------------------------+
        

Figure 30: xmit_packet Packet Header

图30:xmit_数据包头

The poll update routine is called when a valid packet is received and immediately after a poll message has been sent. If in a burst, the poll interval is fixed at 2 s; otherwise, the host poll exponent hpoll is set to the minimum of ppoll from the last packet received and hpoll from the poll routine, but not less than MINPOLL or greater than MAXPOLL. Thus, the clock discipline can be oversampled but not undersampled. This is necessary to preserve subnet dynamic behavior and protect against protocol errors.

当接收到有效数据包并且在发送轮询消息后立即调用轮询更新例程。如果在突发中,轮询间隔固定为2秒;否则,主机轮询指数hpoll设置为来自最后接收的数据包的ppoll和来自轮询例程的hpoll的最小值,但不小于MINPOLL或大于MAXPOLL。因此,时钟规程可以过采样,但不能欠采样。这对于保持子网动态行为和防止协议错误是必要的。

The poll exponent is converted to an interval, which, when added to the last poll time variable, determines the value of the next poll time variable. Finally, the last poll time variable is set to the current seconds counter.

轮询指数将转换为一个间隔,当添加到上一个轮询时间变量时,该间隔将确定下一个轮询时间变量的值。最后,最后一个轮询时间变量设置为当前秒计数器。

14. Simple Network Time Protocol (SNTP)
14. 简单网络时间协议(SNTP)

Primary servers and clients complying with a subset of NTP, called the Simple Network Time Protocol (SNTPv4) [RFC4330], do not need to implement the mitigation algorithms described in Section 9 and following sections. SNTP is intended for primary servers equipped with a single reference clock, as well as for clients with a single upstream server and no dependent clients. The fully developed NTPv4 implementation is intended for secondary servers with multiple upstream servers and multiple downstream servers or clients. Other than these considerations, NTP and SNTP servers and clients are completely interoperable and can be intermixed in NTP subnets.

符合NTP子集(称为简单网络时间协议(SNTPv4)[RFC4330])的主服务器和客户端不需要实现第9节和以下章节中描述的缓解算法。SNTP适用于配备单一参考时钟的主服务器,以及配备单一上游服务器且无依赖客户端的客户端。充分开发的NTPv4实现适用于具有多个上游服务器和多个下游服务器或客户端的辅助服务器。除此之外,NTP和SNTP服务器和客户端完全可互操作,并且可以在NTP子网中混合使用。

An SNTP primary server implementing the on-wire protocol described in Section 8 has no upstream servers except a single reference clock. In principle, it is indistinguishable from an NTP primary server that has the mitigation algorithms and therefore capable of mitigating between multiple reference clocks.

实现第8节所述在线协议的SNTP主服务器除了一个参考时钟之外没有上游服务器。原则上,它与具有缓解算法的NTP主服务器无法区分,因此能够在多个参考时钟之间缓解。

Upon receiving a client request, an SNTP primary server constructs and sends the reply packet as described in Figure 31. Note that the dispersion field in the packet header must be updated as described in Section 5.

在接收到客户机请求后,SNTP主服务器构建并发送回复包,如图31所示。注意,分组报头中的分散字段必须按照第5节所述进行更新。

                   +-----------------------------------+
                   | Packet Variable <--   Variable    |
                   +-----------------------------------+
                   | x.leap        <--     s.leap      |
                   | x.version     <--     r.version   |
                   | x.mode        <--     4           |
                   | x.stratum     <--     s.stratum   |
                   | x.poll        <--     r.poll      |
                   | x.precision   <--     s.precision |
                   | x.rootdelay   <--     s.rootdelay |
                   | x.rootdisp    <--     s.rootdisp  |
                   | x.refid       <--     s.refid     |
                   | x.reftime     <--     s.reftime   |
                   | x.org         <--     r.xmt       |
                   | x.rec         <--     r.dst       |
                   | x.xmt         <--     clock       |
                   | x.keyid       <--     r.keyid     |
                   | x.digest      <--     md5 digest  |
                   +-----------------------------------+
        
                   +-----------------------------------+
                   | Packet Variable <--   Variable    |
                   +-----------------------------------+
                   | x.leap        <--     s.leap      |
                   | x.version     <--     r.version   |
                   | x.mode        <--     4           |
                   | x.stratum     <--     s.stratum   |
                   | x.poll        <--     r.poll      |
                   | x.precision   <--     s.precision |
                   | x.rootdelay   <--     s.rootdelay |
                   | x.rootdisp    <--     s.rootdisp  |
                   | x.refid       <--     s.refid     |
                   | x.reftime     <--     s.reftime   |
                   | x.org         <--     r.xmt       |
                   | x.rec         <--     r.dst       |
                   | x.xmt         <--     clock       |
                   | x.keyid       <--     r.keyid     |
                   | x.digest      <--     md5 digest  |
                   +-----------------------------------+
        

Figure 31: fast_xmit Packet Header

图31:fast_xmit数据包头

An SNTP client implementing the on-wire protocol has a single server and no dependent clients. It can operate with any subset of the NTP on-wire protocol, the simplest approach using only the transmit timestamp of the server packet and ignoring all other fields. However, the additional complexity to implement the full on-wire protocol is minimal so that a full implementation is encouraged.

实现在线协议的SNTP客户端只有一台服务器,没有依赖的客户端。它可以使用NTP在线协议的任何子集进行操作,这是只使用服务器数据包的传输时间戳而忽略所有其他字段的最简单方法。然而,实现完全在线协议的额外复杂性是最小的,因此鼓励完全实现。

15. Security Considerations
15. 安全考虑

NTP security requirements are even more stringent than most other distributed services. First, the operation of the authentication mechanism and the time synchronization mechanism are inextricably intertwined. Reliable time synchronization requires cryptographic keys that are valid only over a designated time interval; but, time intervals can be enforced only when participating servers and clients

NTP安全要求甚至比大多数其他分布式服务更严格。首先,身份验证机制和时间同步机制的运作密不可分。可靠的时间同步需要仅在指定时间间隔内有效的加密密钥;但是,时间间隔只能在参与服务器和客户端时强制执行

are reliably synchronized to UTC. In addition, the NTP subnet is hierarchical by nature, so time and trust flow from the primary servers at the root through secondary servers to the clients at the leaves.

与UTC可靠同步。此外,NTP子网本质上是分层的,因此时间和信任从根节点的主服务器通过辅助服务器流向叶节点的客户端。

An NTP client can claim to have authentic time to dependent applications only if all servers on the path to the primary servers are authenticated. In NTP each server authenticates the next lower stratum servers and authenticates by induction the lowest stratum (primary) servers. It is important to note that authentication in the context of NTP does not necessarily imply the time is correct. An NTP client mobilizes a number of concurrent associations with different servers and uses a crafted agreement algorithm to pluck truechimers from the population possibly including falsetickers.

只有在主服务器路径上的所有服务器都经过身份验证的情况下,NTP客户机才能声明对依赖的应用程序具有真实的时间。在NTP中,每个服务器对下一个较低层服务器进行身份验证,并通过归纳对最低层(主)服务器进行身份验证。需要注意的是,NTP上下文中的身份验证并不一定意味着时间是正确的。NTP客户机与不同的服务器移动大量并发关联,并使用特制的协议算法从人群中提取TrueChemer,可能包括Falsticker。

The NTP specification assumes that the goal of the intruder is to inject false time values, disrupt the protocol, or clog the network, servers, or clients with spurious packets that exhaust resources and deny service to legitimate applications. There are a number of defense mechanisms already built in the NTP architecture, protocol, and algorithms. The on-wire timestamp exchange scheme is inherently resistant to spoofing, packet-loss, and replay attacks. The engineered clock filter, selection and clustering algorithms are designed to defend against evil cliques of Byzantine traitors. While not necessarily designed to defeat determined intruders, these algorithms and accompanying sanity checks have functioned well over the years to deflect improperly operating but presumably friendly scenarios. However, these mechanisms do not securely identify and authenticate servers to clients. Without specific further protection, an intruder can inject any or all of the following attacks:

NTP规范假设入侵者的目标是注入错误的时间值,破坏协议,或使用虚假数据包阻塞网络、服务器或客户端,这些数据包会耗尽资源并拒绝为合法应用程序提供服务。NTP体系结构、协议和算法中已经构建了许多防御机制。在线时间戳交换方案固有地抵抗欺骗、数据包丢失和重放攻击。精心设计的时钟过滤器、选择和聚类算法旨在抵御拜占庭叛徒的邪恶集团。虽然这些算法不一定是为了击败确定的入侵者而设计的,但这些算法和伴随的健全性检查多年来一直发挥着良好的作用,以避免出现操作不当但可能是友好的情况。但是,这些机制不能安全地向客户端识别和验证服务器。在没有特定的进一步保护的情况下,入侵者可以注入以下任何或所有攻击:

1. An intruder can intercept and archive packets forever, as well as all the public values ever generated and transmitted over the net.

1. 入侵者可以永远截获和归档数据包,以及通过网络生成和传输的所有公共值。

2. An intruder can generate packets faster than the server, network or client can process them, especially if they require expensive cryptographic computations.

2. 入侵者生成数据包的速度比服务器、网络或客户端处理数据包的速度要快,特别是当它们需要昂贵的密码计算时。

3. In a wiretap attack, the intruder can intercept, modify, and replay a packet. However, it cannot permanently prevent onward transmission of the original packet; that is, it cannot break the wire, only tell lies and congest it. Generally, the modified packet cannot arrive at the victim before the original packet, nor does it have the server private keys or identity parameters.

3. 在窃听攻击中,入侵者可以拦截、修改和重放数据包。然而,它不能永久地阻止原始数据包的向前传输;也就是说,它不能断开电线,只能说谎并堵塞电线。通常,修改后的数据包不能在原始数据包之前到达受害者,也没有服务器私钥或身份参数。

4. In a middleman or masquerade attack, the intruder is positioned between the server and client, so it can intercept, modify and replay a packet and prevent onward transmission of the original packet. However, the middleman does not have the server private keys.

4. 在中间人或伪装攻击中,入侵者位于服务器和客户端之间,因此它可以拦截、修改和重播数据包,并阻止原始数据包的向前传输。但是,中间人没有服务器私钥。

The NTP security model assumes the following possible limitations:

NTP安全模型假设了以下可能的限制:

1. The running times for public key algorithms are relatively long and highly variable. In general, the performance of the time synchronization function is badly degraded if these algorithms must be used for every NTP packet.

1. 公钥算法的运行时间相对较长且变化很大。通常,如果必须对每个NTP数据包使用这些算法,则时间同步功能的性能会严重降低。

2. In some modes of operation, it is not feasible for a server to retain state variables for every client. It is however feasible to regenerated them for a client upon arrival of a packet from that client.

2. 在某些操作模式下,服务器不可能为每个客户端保留状态变量。然而,在来自客户机的数据包到达时为客户机重新生成它们是可行的。

3. The lifetime of cryptographic values must be enforced, which requires a reliable system clock. However, the sources that synchronize the system clock must be trusted. This circular interdependence of the timekeeping and authentication functions requires special handling.

3. 必须强制执行加密值的生存期,这需要可靠的系统时钟。但是,同步系统时钟的源必须是可信的。计时和身份验证功能的这种循环相互依赖性需要特殊处理。

4. Client security functions must involve only public values transmitted over the net. Private values must never be disclosed beyond the machine on which they were created, except in the case of a special trusted agent (TA) assigned for this purpose.

4. 客户端安全功能必须仅涉及通过网络传输的公共值。私有值不得在创建它们的计算机之外公开,除非为此目的指定了特殊的受信任代理(TA)。

Unlike the Secure Shell (SSH) security model, where the client must be securely authenticated to the server, in NTP the server must be securely authenticated to the client. In SSH, each different interface address can be bound to a different name, as returned by a reverse-DNS query. In this design, separate public/private key pairs may be required for each interface address with a distinct name. A perceived advantage of this design is that the security compartment can be different for each interface. This allows a firewall, for instance, to require some interfaces to authenticate the client and others not.

与Secure Shell(SSH)安全模型不同,在该模型中,客户端必须安全地通过服务器身份验证,而在NTP中,服务器必须安全地通过客户端身份验证。在SSH中,每个不同的接口地址都可以绑定到一个不同的名称,正如反向DNS查询返回的那样。在这种设计中,可能需要为具有不同名称的每个接口地址提供单独的公钥/私钥对。这种设计的一个明显优势是,每个接口的安全隔室可能不同。例如,这允许防火墙需要一些接口来验证客户端,而其他接口则不需要。

In the case of NTP as specified herein, NTP broadcast clients are vulnerable to disruption by misbehaving or hostile SNTP or NTP broadcast servers elsewhere in the Internet. Such disruption can be minimized by several approaches. Filtering can be employed to limit the access of NTP clients to known or trusted NTP broadcast servers. Such filtering will prevent malicious traffic from reaching the NTP clients. Cryptographic authentication at the client will only allow

在本文规定的NTP情况下,NTP广播客户端容易受到行为不端或恶意SNTP或互联网其他地方NTP广播服务器的干扰。这种干扰可以通过几种方法最小化。过滤可用于限制NTP客户端对已知或受信任的NTP广播服务器的访问。这种过滤将防止恶意流量到达NTP客户端。客户端的加密身份验证将只允许

timing information from properly signed NTP messages to be utilized in synchronizing its clock. Higher levels of authentication may be gained by the use of the Autokey mechanism [RFC5906].

来自正确签名的NTP消息的定时信息,用于同步其时钟。通过使用自动密钥机制[RFC5906],可以获得更高级别的身份验证。

Section 8 describes a potential security concern with the replay of client requests. Following the recommendations in that section provides protection against such attacks.

第8节描述了客户端请求重播的潜在安全问题。遵循该节中的建议可防止此类攻击。

It should be noted that this specification is describing an existing implementation. While the security shortfalls of the MD5 algorithm are well-known, its use in the NTP specification is consistent with widescale deployment in the Internet community.

应该注意的是,本规范描述的是一个现有的实现。虽然MD5算法的安全缺陷是众所周知的,但它在NTP规范中的使用与互联网社区中的大规模部署是一致的。

16. IANA Considerations
16. IANA考虑

UDP/TCP Port 123 was previously assigned by IANA for this protocol. The IANA has assigned the IPv4 multicast group address 224.0.1.1 and the IPv6 multicast address ending :101 for NTP. This document introduces NTP extension fields allowing for the development of future extensions to the protocol, where a particular extension is to be identified by the Field Type sub-field within the extension field. IANA has established and will maintain a registry for Extension Field Types associated with this protocol, populating this registry with no initial entries. As future needs arise, new Extension Field Types may be defined. Following the policies outlined in [RFC5226], new values are to be defined by IETF Review.

UDP/TCP端口123以前由IANA为此协议分配。IANA已为NTP分配了IPv4多播组地址224.0.1.1和IPv6多播地址结束:101。本文档介绍了NTP扩展字段,允许开发协议的未来扩展,其中特定扩展由扩展字段中的字段类型子字段标识。IANA已建立并将维护与此协议关联的扩展字段类型的注册表,该注册表中没有初始条目。随着未来的需要,可能会定义新的扩展字段类型。按照[RFC5226]中概述的政策,新值将由IETF评审定义。

The IANA has created a new registry for NTP Reference Identifier codes. This includes the current codes defined in Section 7.3, and may be extended on a First-Come-First-Serve (FCFS) basis. The format of the registry is:

IANA已经为NTP参考标识符代码创建了一个新的注册表。这包括第7.3节中定义的现行规范,可在先到先得(FCFS)的基础上进行扩展。登记册的格式如下:

     +------+----------------------------------------------------------+
     | ID   | Clock Source                                             |
     +------+----------------------------------------------------------+
     | GOES | Geosynchronous Orbit Environment Satellite               |
     | GPS  | Global Position System                                   |
     | ...  | ...                                                      |
     +------+----------------------------------------------------------+
        
     +------+----------------------------------------------------------+
     | ID   | Clock Source                                             |
     +------+----------------------------------------------------------+
     | GOES | Geosynchronous Orbit Environment Satellite               |
     | GPS  | Global Position System                                   |
     | ...  | ...                                                      |
     +------+----------------------------------------------------------+
        

Figure 32: Reference Identifier Codes

图32:参考标识符代码

The IANA has created a new registry for NTP Kiss-o'-Death codes. This includes the current codes defined in Section 7.4, and may be extended on a FCFS basis. The format of the registry is:

IANA已经为NTP Kiss-o'-死亡代码创建了一个新的注册表。这包括第7.4节中定义的现行规范,可在FCFS基础上进行扩展。登记册的格式如下:

   +------+------------------------------------------------------------+
   | Code |                           Meaning                          |
   +------+------------------------------------------------------------+
   | ACST | The association belongs to a unicast server.               |
   | AUTH | Server authentication failed.                              |
   | ...  | ...                                                        |
   +------+------------------------------------------------------------+
        
   +------+------------------------------------------------------------+
   | Code |                           Meaning                          |
   +------+------------------------------------------------------------+
   | ACST | The association belongs to a unicast server.               |
   | AUTH | Server authentication failed.                              |
   | ...  | ...                                                        |
   +------+------------------------------------------------------------+
        

Figure 33: Kiss Codes

图33:Kiss代码

For both Reference Identifiers and Kiss-o'-Death codes, IANA is requested to never assign a code beginning with the character "X", as this is reserved for experimentation and development.

对于参考标识符和Kiss-o'-死亡代码,IANA被要求从不分配以字符“X”开头的代码,因为这是为实验和开发保留的。

17. Acknowledgements
17. 致谢

The editors would like to thank Karen O'Donoghue, Brian Haberman, Greg Dowd, Mark Elliot, Harlan Stenn, Yaakov Stein, Stewart Bryant, and Danny Mayer for technical reviews and specific text contributions to this document.

编辑们要感谢Karen O'Donoghue、Brian Haberman、Greg Dowd、Mark Elliot、Harlan Stenn、Yaakov Stein、Stewart Bryant和Danny Mayer对本文件的技术评论和具体文本贡献。

18. References
18. 工具书类
18.1. Normative References
18.1. 规范性引用文件

[RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980.

[RFC0768]Postel,J.,“用户数据报协议”,STD 6,RFC 768,1980年8月。

[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

[RFC0791]Postel,J.,“互联网协议”,STD 5,RFC 7911981年9月。

[RFC0793] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.

[RFC0793]Postel,J.,“传输控制协议”,标准7,RFC 793,1981年9月。

[RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992.

[RFC1321]Rivest,R.,“MD5消息摘要算法”,RFC13211992年4月。

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2119]Bradner,S.,“RFC中用于表示需求水平的关键词”,BCP 14,RFC 2119,1997年3月。

18.2. Informative References
18.2. 资料性引用

[CGPM] Bureau International des Poids et Mesures, "Comptes Rendus de la 15e CGPM", 1976.

[CGPM]国际警察与测量局,“15e CGPM警察局”,1976年。

[ITU-R_TF.460] International Telecommunications Union, "ITU-R TF.460 Standard-frequency and time-signal emissions", February 2002.

[ITU-R_TF.460]国际电信联盟,“ITU-R TF.460标准频率和时间信号发射”,2002年2月。

[RFC1305] Mills, D., "Network Time Protocol (Version 3) Specification, Implementation and Analysis", RFC 1305, March 1992.

[RFC1305]Mills,D.,“网络时间协议(第3版)规范、实施和分析”,RFC1305,1992年3月。

[RFC1345] Simonsen, K., "Character Mnemonics and Character Sets", RFC 1345, June 1992.

[RFC1345]Simonsen,K.,“字符助记符和字符集”,RFC13451992年6月。

[RFC4330] Mills, D., "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI", RFC 4330, January 2006.

[RFC4330]Mills,D.“IPv4、IPv6和OSI的简单网络时间协议(SNTP)第4版”,RFC 4330,2006年1月。

[RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 5226, May 2008.

[RFC5226]Narten,T.和H.Alvestrand,“在RFCs中编写IANA注意事项部分的指南”,BCP 26,RFC 5226,2008年5月。

[RFC5906] Haberman, B., Ed. and D. Mills, "Network Time Protocol Version 4: Autokey Specification", RFC 5906, June 2010.

[RFC5906]Haberman,B.,Ed.和D.Mills,“网络时间协议第4版:自动密钥规范”,RFC 59062010年6月。

[ref6] Marzullo and S. Owicki, "Maintaining the time in a distributed system", ACM Operating Systems Review 19, July 1985.

[参考文献6]Marzullo和S.Owicki,“在分布式系统中维护时间”,《ACM操作系统评论》,1985年7月19日。

[ref7] Mills, D.L., "Computer Network Time Synchronization - the Network Time Protocol", CRC Press, 304 pp, 2006.

[参考文献7]米尔斯,D.L.,“计算机网络时间同步-网络时间协议”,华润出版,304页,2006年。

[ref9] Mills, D.L., Electrical and Computer Engineering Technical Report 06-6-1, NDSS, June 2006, "Network Time Protocol Version 4 Reference and Implementation Guide", 2006.

[参考文献9]Mills,D.L.,电气和计算机工程技术报告06-6-1,NDSS,2006年6月,“网络时间协议版本4参考和实施指南”,2006年。

Appendix A. Code Skeleton
附录A.代码框架

This appendix is intended to describe the protocol and algorithms of an implementation in a general way using what is called a code skeleton program. This consists of a set of definitions, structures, and code fragments that illustrate the protocol operations without the complexities of an actual implementation of the protocol. This program is not an executable and is not designed to run in the ordinary sense.

本附录旨在使用所谓的代码框架程序,以一般方式描述实现的协议和算法。它由一组定义、结构和代码片段组成,这些定义、结构和代码片段演示了协议操作,而不需要协议的实际实现的复杂性。这个程序不是一个可执行文件,也不是设计用来在普通意义上运行的。

Most of the features of the reference implementation are included here, with the following exceptions: there are no provisions for reference clocks or public key (Autokey) cryptography. There is no huff-n'-puff filter, anti-clockhop hysteresis, or monitoring provisions. Many of the values that can be tinkered in the reference implementation are assumed constants here. There are only minimal provisions for the kiss-o'-death packet and no responding code.

这里包括参考实现的大部分功能,但有以下例外:没有关于参考时钟或公钥(自动密钥)加密的规定。没有吹扫过滤器、防时钟跳滞后或监控规定。在参考实现中可以修改的许多值在此假定为常量。对于kiss-o'-死亡数据包只有最低限度的规定,没有响应代码。

The program is not intended to be fast or compact, just to demonstrate the algorithms with sufficient fidelity to understand how they work. The code skeleton consists of eight segments, a header segment included by each of the other segments, plus a code segment for the main program, kernel I/O and system clock interfaces, and peer, system, clock_adjust, and poll processes. These are presented in order below along with definitions and variables specific to each process.

该程序不是为了快速或紧凑,只是为了以足够的保真度演示算法,以了解它们是如何工作的。代码框架由八个段组成,其中一个头段包含在每个其他段中,另外一个代码段用于主程序、内核I/O和系统时钟接口以及对等、系统、时钟调整和轮询进程。下面按顺序列出了这些流程以及每个流程的特定定义和变量。

A.1. Global Definitions
A.1. 全球定义
A.1.1. Definitions, Constants, Parameters
A.1.1. 定义、常数、参数
#include <math.h>               /* avoids complaints about sqrt() */
#include <sys/time.h>           /* for gettimeofday() and friends */
#include <stdlib.h>             /* for malloc() and friends */
#include <string.h>             /* for memset() */
        
#include <math.h>               /* avoids complaints about sqrt() */
#include <sys/time.h>           /* for gettimeofday() and friends */
#include <stdlib.h>             /* for malloc() and friends */
#include <string.h>             /* for memset() */
        
/*
 * Data types
 *
 * This program assumes the int data type is 32 bits and the long data
 * type is 64 bits.  The native data type used in most calculations is
 * floating double.  The data types used in some packet header fields
 * require conversion to and from this representation.  Some header
 * fields involve partitioning an octet, here represented by individual
 * octets.
 *
 * The 64-bit NTP timestamp format used in timestamp calculations is
 * unsigned seconds and fraction with the decimal point to the left of
        
/*
 * Data types
 *
 * This program assumes the int data type is 32 bits and the long data
 * type is 64 bits.  The native data type used in most calculations is
 * floating double.  The data types used in some packet header fields
 * require conversion to and from this representation.  Some header
 * fields involve partitioning an octet, here represented by individual
 * octets.
 *
 * The 64-bit NTP timestamp format used in timestamp calculations is
 * unsigned seconds and fraction with the decimal point to the left of
        
 * bit 32.  The only operation permitted with these values is
 * subtraction, yielding a signed 31-bit difference.  The 32-bit NTP
 * short format used in delay and dispersion calculations is seconds and
 * fraction with the decimal point to the left of bit 16.  The only
 * operations permitted with these values are addition and
 * multiplication by a constant.
 *
 * The IPv4 address is 32 bits, while the IPv6 address is 128 bits.  The
 * message digest field is 128 bits as constructed by the MD5 algorithm.
 * The precision and poll interval fields are signed log2 seconds.
 */
typedef unsigned long long tstamp;   /* NTP timestamp format */
typedef unsigned int tdist;     /* NTP short format */
typedef unsigned long ipaddr;   /* IPv4 or IPv6 address */
typedef unsigned long digest;   /* md5 digest */
typedef signed char s_char;     /* precision and poll interval (log2) */
        
 * bit 32.  The only operation permitted with these values is
 * subtraction, yielding a signed 31-bit difference.  The 32-bit NTP
 * short format used in delay and dispersion calculations is seconds and
 * fraction with the decimal point to the left of bit 16.  The only
 * operations permitted with these values are addition and
 * multiplication by a constant.
 *
 * The IPv4 address is 32 bits, while the IPv6 address is 128 bits.  The
 * message digest field is 128 bits as constructed by the MD5 algorithm.
 * The precision and poll interval fields are signed log2 seconds.
 */
typedef unsigned long long tstamp;   /* NTP timestamp format */
typedef unsigned int tdist;     /* NTP short format */
typedef unsigned long ipaddr;   /* IPv4 or IPv6 address */
typedef unsigned long digest;   /* md5 digest */
typedef signed char s_char;     /* precision and poll interval (log2) */
        
/*
 * Timestamp conversion macroni
 */
#define FRIC        65536.                  /* 2^16 as a double */
#define D2FP(r)     ((tdist)((r) * FRIC))   /* NTP short */
#define FP2D(r)     ((double)(r) / FRIC)
        
/*
 * Timestamp conversion macroni
 */
#define FRIC        65536.                  /* 2^16 as a double */
#define D2FP(r)     ((tdist)((r) * FRIC))   /* NTP short */
#define FP2D(r)     ((double)(r) / FRIC)
        
#define FRAC       4294967296.             /* 2^32 as a double */
#define D2LFP(a)   ((tstamp)((a) * FRAC))  /* NTP timestamp */
#define LFP2D(a)   ((double)(a) / FRAC)
#define U2LFP(a)   (((unsigned long long) \
                       ((a).tv_sec + JAN_1970) << 32) + \
                       (unsigned long long) \
                       ((a).tv_usec / 1e6 * FRAC))
        
#define FRAC       4294967296.             /* 2^32 as a double */
#define D2LFP(a)   ((tstamp)((a) * FRAC))  /* NTP timestamp */
#define LFP2D(a)   ((double)(a) / FRAC)
#define U2LFP(a)   (((unsigned long long) \
                       ((a).tv_sec + JAN_1970) << 32) + \
                       (unsigned long long) \
                       ((a).tv_usec / 1e6 * FRAC))
        
/*
 * Arithmetic conversions
 */
#define LOG2D(a)        ((a) < 0 ? 1. / (1L << -(a)) : \
                            1L << (a))          /* poll, etc. */
#define SQUARE(x)       (x * x)
#define SQRT(x)         (sqrt(x))
        
/*
 * Arithmetic conversions
 */
#define LOG2D(a)        ((a) < 0 ? 1. / (1L << -(a)) : \
                            1L << (a))          /* poll, etc. */
#define SQUARE(x)       (x * x)
#define SQRT(x)         (sqrt(x))
        
/*
 * Global constants.  Some of these might be converted to variables
 * that can be tinkered by configuration or computed on-the-fly.  For
 * instance, the reference implementation computes PRECISION on-the-fly
 * and provides performance tuning for the defines marked with % below.
 */
#define VERSION         4       /* version number */
#define MINDISP         .01     /* % minimum dispersion (s) */
        
/*
 * Global constants.  Some of these might be converted to variables
 * that can be tinkered by configuration or computed on-the-fly.  For
 * instance, the reference implementation computes PRECISION on-the-fly
 * and provides performance tuning for the defines marked with % below.
 */
#define VERSION         4       /* version number */
#define MINDISP         .01     /* % minimum dispersion (s) */
        
#define MAXDISP         16      /* maximum dispersion (s) */
#define MAXDIST         1       /* % distance threshold (s) */
#define NOSYNC          0x3     /* leap unsync */
#define MAXSTRAT        16      /* maximum stratum (infinity metric) */
#define MINPOLL         6       /* % minimum poll interval (64 s)*/
#define MAXPOLL         17      /* % maximum poll interval (36.4 h) */
#define MINCLOCK        3       /* minimum manycast survivors */
#define MAXCLOCK        10      /* maximum manycast candidates */
#define TTLMAX          8       /* max ttl manycast */
#define BEACON          15      /* max interval between beacons */
        
#define MAXDISP         16      /* maximum dispersion (s) */
#define MAXDIST         1       /* % distance threshold (s) */
#define NOSYNC          0x3     /* leap unsync */
#define MAXSTRAT        16      /* maximum stratum (infinity metric) */
#define MINPOLL         6       /* % minimum poll interval (64 s)*/
#define MAXPOLL         17      /* % maximum poll interval (36.4 h) */
#define MINCLOCK        3       /* minimum manycast survivors */
#define MAXCLOCK        10      /* maximum manycast candidates */
#define TTLMAX          8       /* max ttl manycast */
#define BEACON          15      /* max interval between beacons */
        
#define PHI             15e-6   /* % frequency tolerance (15 ppm) */
#define NSTAGE          8       /* clock register stages */
#define NMAX            50      /* maximum number of peers */
#define NSANE           1       /* % minimum intersection survivors */
#define NMIN            3       /* % minimum cluster survivors */
        
#define PHI             15e-6   /* % frequency tolerance (15 ppm) */
#define NSTAGE          8       /* clock register stages */
#define NMAX            50      /* maximum number of peers */
#define NSANE           1       /* % minimum intersection survivors */
#define NMIN            3       /* % minimum cluster survivors */
        
/*
 * Global return values
 */
#define TRUE            1       /* boolean true */
#define FALSE           0       /* boolean false */
        
/*
 * Global return values
 */
#define TRUE            1       /* boolean true */
#define FALSE           0       /* boolean false */
        
/*
 * Local clock process return codes
 */
#define IGNORE          0       /* ignore */
#define SLEW            1       /* slew adjustment */
#define STEP            2       /* step adjustment */
#define PANIC           3       /* panic - no adjustment */
        
/*
 * Local clock process return codes
 */
#define IGNORE          0       /* ignore */
#define SLEW            1       /* slew adjustment */
#define STEP            2       /* step adjustment */
#define PANIC           3       /* panic - no adjustment */
        
/*
 * System flags
 */
#define S_FLAGS         0       /* any system flags */
#define S_BCSTENAB      0x1     /* enable broadcast client */
        
/*
 * System flags
 */
#define S_FLAGS         0       /* any system flags */
#define S_BCSTENAB      0x1     /* enable broadcast client */
        
/*
 * Peer flags
 */
#define P_FLAGS         0       /* any peer flags */
#define P_EPHEM         0x01    /* association is ephemeral */
#define P_BURST         0x02    /* burst enable */
#define P_IBURST        0x04    /* intial burst enable */
#define P_NOTRUST       0x08    /* authenticated access */
#define P_NOPEER        0x10    /* authenticated mobilization */
#define P_MANY          0x20    /* manycast client */
        
/*
 * Peer flags
 */
#define P_FLAGS         0       /* any peer flags */
#define P_EPHEM         0x01    /* association is ephemeral */
#define P_BURST         0x02    /* burst enable */
#define P_IBURST        0x04    /* intial burst enable */
#define P_NOTRUST       0x08    /* authenticated access */
#define P_NOPEER        0x10    /* authenticated mobilization */
#define P_MANY          0x20    /* manycast client */
        
/*
 * Authentication codes
 */
#define A_NONE          0       /* no authentication */
#define A_OK            1       /* authentication OK */
#define A_ERROR         2       /* authentication error */
#define A_CRYPTO        3       /* crypto-NAK */
        
/*
 * Authentication codes
 */
#define A_NONE          0       /* no authentication */
#define A_OK            1       /* authentication OK */
#define A_ERROR         2       /* authentication error */
#define A_CRYPTO        3       /* crypto-NAK */
        
/*
 * Association state codes
 */
#define X_INIT          0       /* initialization */
#define X_STALE         1       /* timeout */
#define X_STEP          2       /* time step */
#define X_ERROR         3       /* authentication error */
#define X_CRYPTO        4       /* crypto-NAK received */
#define X_NKEY          5       /* untrusted key */
        
/*
 * Association state codes
 */
#define X_INIT          0       /* initialization */
#define X_STALE         1       /* timeout */
#define X_STEP          2       /* time step */
#define X_ERROR         3       /* authentication error */
#define X_CRYPTO        4       /* crypto-NAK received */
#define X_NKEY          5       /* untrusted key */
        
/*
 * Protocol mode definitions
 */
#define M_RSVD          0       /* reserved */
#define M_SACT          1       /* symmetric active */
#define M_PASV          2       /* symmetric passive */
#define M_CLNT          3       /* client */
#define M_SERV          4       /* server */
#define M_BCST          5       /* broadcast server */
#define M_BCLN          6       /* broadcast client */
        
/*
 * Protocol mode definitions
 */
#define M_RSVD          0       /* reserved */
#define M_SACT          1       /* symmetric active */
#define M_PASV          2       /* symmetric passive */
#define M_CLNT          3       /* client */
#define M_SERV          4       /* server */
#define M_BCST          5       /* broadcast server */
#define M_BCLN          6       /* broadcast client */
        
/*
 * Clock state definitions
 */
#define NSET            0       /* clock never set */
#define FSET            1       /* frequency set from file */
#define SPIK            2       /* spike detected */
#define FREQ            3       /* frequency mode */
#define SYNC            4       /* clock synchronized */
        
/*
 * Clock state definitions
 */
#define NSET            0       /* clock never set */
#define FSET            1       /* frequency set from file */
#define SPIK            2       /* spike detected */
#define FREQ            3       /* frequency mode */
#define SYNC            4       /* clock synchronized */
        
#define min(a, b)   ((a) < (b) ? (a) : (b))
#define max(a, b)   ((a) < (b) ? (b) : (a))
        
#define min(a, b)   ((a) < (b) ? (a) : (b))
#define max(a, b)   ((a) < (b) ? (b) : (a))
        
A.1.2. Packet Data Structures
A.1.2. 分组数据结构
/*
 * The receive and transmit packets may contain an optional message
 * authentication code (MAC) consisting of a key identifier (keyid) and
 * message digest (mac in the receive structure and dgst in the transmit
 * structure).  NTPv4 supports optional extension fields that
 * are inserted after the header and before the MAC, but these are
 * not described here.
 *
 * Receive packet
 *
 * Note the dst timestamp is not part of the packet itself.  It is
 * captured upon arrival and returned in the receive buffer along with
 * the buffer length and data.  Note that some of the char fields are
 * packed in the actual header, but the details are omitted here.
 */
struct r {
        ipaddr  srcaddr;        /* source (remote) address */
        ipaddr  dstaddr;        /* destination (local) address */
        char    version;        /* version number */
        char    leap;           /* leap indicator */
        char    mode;           /* mode */
        char    stratum;        /* stratum */
        char    poll;           /* poll interval */
        s_char  precision;      /* precision */
        tdist   rootdelay;      /* root delay */
        tdist   rootdisp;       /* root dispersion */
        char    refid;          /* reference ID */
        tstamp  reftime;        /* reference time */
        tstamp  org;            /* origin timestamp */
        tstamp  rec;            /* receive timestamp */
        tstamp  xmt;            /* transmit timestamp */
        int     keyid;          /* key ID */
        digest  mac;            /* message digest */
        tstamp  dst;            /* destination timestamp */
} r;
        
/*
 * The receive and transmit packets may contain an optional message
 * authentication code (MAC) consisting of a key identifier (keyid) and
 * message digest (mac in the receive structure and dgst in the transmit
 * structure).  NTPv4 supports optional extension fields that
 * are inserted after the header and before the MAC, but these are
 * not described here.
 *
 * Receive packet
 *
 * Note the dst timestamp is not part of the packet itself.  It is
 * captured upon arrival and returned in the receive buffer along with
 * the buffer length and data.  Note that some of the char fields are
 * packed in the actual header, but the details are omitted here.
 */
struct r {
        ipaddr  srcaddr;        /* source (remote) address */
        ipaddr  dstaddr;        /* destination (local) address */
        char    version;        /* version number */
        char    leap;           /* leap indicator */
        char    mode;           /* mode */
        char    stratum;        /* stratum */
        char    poll;           /* poll interval */
        s_char  precision;      /* precision */
        tdist   rootdelay;      /* root delay */
        tdist   rootdisp;       /* root dispersion */
        char    refid;          /* reference ID */
        tstamp  reftime;        /* reference time */
        tstamp  org;            /* origin timestamp */
        tstamp  rec;            /* receive timestamp */
        tstamp  xmt;            /* transmit timestamp */
        int     keyid;          /* key ID */
        digest  mac;            /* message digest */
        tstamp  dst;            /* destination timestamp */
} r;
        
/*
 * Transmit packet
 */
struct x {
        ipaddr  dstaddr;        /* source (local) address */
        ipaddr  srcaddr;        /* destination (remote) address */
        char    version;        /* version number */
        char    leap;           /* leap indicator */
        char    mode;           /* mode */
        char    stratum;        /* stratum */
        
/*
 * Transmit packet
 */
struct x {
        ipaddr  dstaddr;        /* source (local) address */
        ipaddr  srcaddr;        /* destination (remote) address */
        char    version;        /* version number */
        char    leap;           /* leap indicator */
        char    mode;           /* mode */
        char    stratum;        /* stratum */
        
        char    poll;           /* poll interval */
        s_char  precision;      /* precision */
        tdist   rootdelay;      /* root delay */
        tdist   rootdisp;       /* root dispersion */
        char    refid;          /* reference ID */
        tstamp  reftime;        /* reference time */
        tstamp  org;            /* origin timestamp */
        tstamp  rec;            /* receive timestamp */
        tstamp  xmt;            /* transmit timestamp */
        int     keyid;          /* key ID */
        digest  dgst;           /* message digest */
} x;
        
        char    poll;           /* poll interval */
        s_char  precision;      /* precision */
        tdist   rootdelay;      /* root delay */
        tdist   rootdisp;       /* root dispersion */
        char    refid;          /* reference ID */
        tstamp  reftime;        /* reference time */
        tstamp  org;            /* origin timestamp */
        tstamp  rec;            /* receive timestamp */
        tstamp  xmt;            /* transmit timestamp */
        int     keyid;          /* key ID */
        digest  dgst;           /* message digest */
} x;
        
A.1.3. Association Data Structures
A.1.3. 关联数据结构
   /*
    * Filter stage structure.  Note the t member in this and other
    * structures refers to process time, not real time.  Process time
    * increments by one second for every elapsed second of real time.
    */
   struct f {
           tstamp  t;              /* update time */
           double  offset;         /* clock ofset */
           double  delay;          /* roundtrip delay */
           double  disp;           /* dispersion */
   } f;
        
   /*
    * Filter stage structure.  Note the t member in this and other
    * structures refers to process time, not real time.  Process time
    * increments by one second for every elapsed second of real time.
    */
   struct f {
           tstamp  t;              /* update time */
           double  offset;         /* clock ofset */
           double  delay;          /* roundtrip delay */
           double  disp;           /* dispersion */
   } f;
        
   /*
    * Association structure.  This is shared between the peer process
    * and poll process.
    */
   struct p {
        
   /*
    * Association structure.  This is shared between the peer process
    * and poll process.
    */
   struct p {
        
           /*
            * Variables set by configuration
            */
           ipaddr  srcaddr;        /* source (remote) address */
           ipaddr  dstaddr;        /* destination (local) address */
           char    version;        /* version number */
           char    hmode;          /* host mode */
           int     keyid;          /* key identifier */
           int     flags;          /* option flags */
        
           /*
            * Variables set by configuration
            */
           ipaddr  srcaddr;        /* source (remote) address */
           ipaddr  dstaddr;        /* destination (local) address */
           char    version;        /* version number */
           char    hmode;          /* host mode */
           int     keyid;          /* key identifier */
           int     flags;          /* option flags */
        
           /*
            * Variables set by received packet
            */
           char    leap;           /* leap indicator */
           char    pmode;          /* peer mode */
        
           /*
            * Variables set by received packet
            */
           char    leap;           /* leap indicator */
           char    pmode;          /* peer mode */
        
           char    stratum;        /* stratum */
           char    ppoll;          /* peer poll interval */
           double  rootdelay;      /* root delay */
           double  rootdisp;       /* root dispersion */
           char    refid;          /* reference ID */
           tstamp  reftime;        /* reference time */
   #define begin_clear org         /* beginning of clear area */
           tstamp  org;            /* originate timestamp */
           tstamp  rec;            /* receive timestamp */
           tstamp  xmt;            /* transmit timestamp */
        
           char    stratum;        /* stratum */
           char    ppoll;          /* peer poll interval */
           double  rootdelay;      /* root delay */
           double  rootdisp;       /* root dispersion */
           char    refid;          /* reference ID */
           tstamp  reftime;        /* reference time */
   #define begin_clear org         /* beginning of clear area */
           tstamp  org;            /* originate timestamp */
           tstamp  rec;            /* receive timestamp */
           tstamp  xmt;            /* transmit timestamp */
        
           /*
            * Computed data
            */
           double  t;              /* update time */
           struct f f[NSTAGE];     /* clock filter */
           double  offset;         /* peer offset */
           double  delay;          /* peer delay */
           double  disp;           /* peer dispersion */
           double  jitter;         /* RMS jitter */
        
           /*
            * Computed data
            */
           double  t;              /* update time */
           struct f f[NSTAGE];     /* clock filter */
           double  offset;         /* peer offset */
           double  delay;          /* peer delay */
           double  disp;           /* peer dispersion */
           double  jitter;         /* RMS jitter */
        
           /*
            * Poll process variables
            */
           char    hpoll;          /* host poll interval */
           int     burst;          /* burst counter */
           int     reach;          /* reach register */
           int     ttl;            /* ttl (manycast) */
   #define end_clear unreach       /* end of clear area */
           int     unreach;        /* unreach counter */
           int     outdate;        /* last poll time */
           int     nextdate;       /* next poll time */
   } p;
        
           /*
            * Poll process variables
            */
           char    hpoll;          /* host poll interval */
           int     burst;          /* burst counter */
           int     reach;          /* reach register */
           int     ttl;            /* ttl (manycast) */
   #define end_clear unreach       /* end of clear area */
           int     unreach;        /* unreach counter */
           int     outdate;        /* last poll time */
           int     nextdate;       /* next poll time */
   } p;
        
A.1.4. System Data Structures
A.1.4. 系统数据结构
   /*
    * Chime list.  This is used by the intersection algorithm.
    */
   struct m {                      /* m is for Marzullo */
           struct p *p;            /* peer structure pointer */
           int     type;           /* high +1, mid 0, low -1 */
           double  edge;           /* correctness interval edge */
   } m;
        
   /*
    * Chime list.  This is used by the intersection algorithm.
    */
   struct m {                      /* m is for Marzullo */
           struct p *p;            /* peer structure pointer */
           int     type;           /* high +1, mid 0, low -1 */
           double  edge;           /* correctness interval edge */
   } m;
        
   /*
    * Survivor list.  This is used by the clustering algorithm.
    */
   struct v {
           struct p *p;            /* peer structure pointer */
           double  metric;         /* sort metric */
   } v;
        
   /*
    * Survivor list.  This is used by the clustering algorithm.
    */
   struct v {
           struct p *p;            /* peer structure pointer */
           double  metric;         /* sort metric */
   } v;
        
   /*
    * System structure
    */
   struct s {
           tstamp  t;              /* update time */
           char    leap;           /* leap indicator */
           char    stratum;        /* stratum */
           char    poll;           /* poll interval */
           char    precision;      /* precision */
           double  rootdelay;      /* root delay */
           double  rootdisp;       /* root dispersion */
           char    refid;          /* reference ID */
           tstamp  reftime;        /* reference time */
           struct m m[NMAX];       /* chime list */
           struct v v[NMAX];       /* survivor list */
           struct p *p;            /* association ID */
           double  offset;         /* combined offset */
           double  jitter;         /* combined jitter */
           int     flags;          /* option flags */
           int     n;              /* number of survivors */
   } s;
        
   /*
    * System structure
    */
   struct s {
           tstamp  t;              /* update time */
           char    leap;           /* leap indicator */
           char    stratum;        /* stratum */
           char    poll;           /* poll interval */
           char    precision;      /* precision */
           double  rootdelay;      /* root delay */
           double  rootdisp;       /* root dispersion */
           char    refid;          /* reference ID */
           tstamp  reftime;        /* reference time */
           struct m m[NMAX];       /* chime list */
           struct v v[NMAX];       /* survivor list */
           struct p *p;            /* association ID */
           double  offset;         /* combined offset */
           double  jitter;         /* combined jitter */
           int     flags;          /* option flags */
           int     n;              /* number of survivors */
   } s;
        
A.1.5. Local Clock Data Structures
A.1.5. 本地时钟数据结构
   /*
    * Local clock structure
    */
   struct c {
           tstamp  t;              /* update time */
           int     state;          /* current state */
           double  offset;         /* current offset */
           double  last;           /* previous offset */
           int     count;          /* jiggle counter */
           double  freq;           /* frequency */
           double  jitter;         /* RMS jitter */
           double  wander;         /* RMS wander */
   } c;
        
   /*
    * Local clock structure
    */
   struct c {
           tstamp  t;              /* update time */
           int     state;          /* current state */
           double  offset;         /* current offset */
           double  last;           /* previous offset */
           int     count;          /* jiggle counter */
           double  freq;           /* frequency */
           double  jitter;         /* RMS jitter */
           double  wander;         /* RMS wander */
   } c;
        
A.1.6. Function Prototypes
A.1.6. 函数原型
  /*
   * Peer process
   */
  void    receive(struct r *);    /* receive packet */
  void    packet(struct p *, struct r *); /* process packet */
  void    clock_filter(struct p *, double, double, double); /* filter */
  double  root_dist(struct p *);  /* calculate root distance */
  int     fit(struct p *);        /* determine fitness of server */
  void    clear(struct p *, int); /* clear association */
  int     access(struct r *);     /* determine access restrictions */
        
  /*
   * Peer process
   */
  void    receive(struct r *);    /* receive packet */
  void    packet(struct p *, struct r *); /* process packet */
  void    clock_filter(struct p *, double, double, double); /* filter */
  double  root_dist(struct p *);  /* calculate root distance */
  int     fit(struct p *);        /* determine fitness of server */
  void    clear(struct p *, int); /* clear association */
  int     access(struct r *);     /* determine access restrictions */
        
  /*
   * System process
   */
  int     main();                 /* main program */
  void    clock_select();         /* find the best clocks */
  void    clock_update(struct p *); /* update the system clock */
  void    clock_combine();        /* combine the offsets */
        
  /*
   * System process
   */
  int     main();                 /* main program */
  void    clock_select();         /* find the best clocks */
  void    clock_update(struct p *); /* update the system clock */
  void    clock_combine();        /* combine the offsets */
        
  /*
   * Local clock process
   */
  int     local_clock(struct p *, double); /* clock discipline */
  void    rstclock(int, double, double); /* clock state transition */
        
  /*
   * Local clock process
   */
  int     local_clock(struct p *, double); /* clock discipline */
  void    rstclock(int, double, double); /* clock state transition */
        
  /*
   * Clock adjust process
   */
  void    clock_adjust();         /* one-second timer process */
        
  /*
   * Clock adjust process
   */
  void    clock_adjust();         /* one-second timer process */
        
  /*
   * Poll process
   */
  void    poll(struct p *);               /* poll process */
  void    poll_update(struct p *, int); /* update the poll interval */
  void    peer_xmit(struct p *);  /* transmit a packet */
  void    fast_xmit(struct r *, int, int); /* transmit a reply packet */
        
  /*
   * Poll process
   */
  void    poll(struct p *);               /* poll process */
  void    poll_update(struct p *, int); /* update the poll interval */
  void    peer_xmit(struct p *);  /* transmit a packet */
  void    fast_xmit(struct r *, int, int); /* transmit a reply packet */
        
  /*
   * Utility routines
   */
  digest  md5(int);               /* generate a message digest */
  struct p *mobilize(ipaddr, ipaddr, int, int, int, int); /* mobilize */
  struct p *find_assoc(struct r *); /* search the association table */
        
  /*
   * Utility routines
   */
  digest  md5(int);               /* generate a message digest */
  struct p *mobilize(ipaddr, ipaddr, int, int, int, int); /* mobilize */
  struct p *find_assoc(struct r *); /* search the association table */
        
  /*
   * Kernel interface
   */
  struct r *recv_packet();        /* wait for packet */
  void    xmit_packet(struct x *); /* send packet */
  void    step_time(double);      /* step time */
  void    adjust_time(double);    /* adjust (slew) time */
  tstamp  get_time();             /* read time */
        
  /*
   * Kernel interface
   */
  struct r *recv_packet();        /* wait for packet */
  void    xmit_packet(struct x *); /* send packet */
  void    step_time(double);      /* step time */
  void    adjust_time(double);    /* adjust (slew) time */
  tstamp  get_time();             /* read time */
        
A.2. Main Program and Utility Routines
A.2. 主程序和实用程序
/*
 * Definitions
 */
#define PRECISION       -18     /* precision (log2 s)  */
#define IPADDR          0       /* any IP address */
#define MODE            0       /* any NTP mode */
#define KEYID           0       /* any key identifier */
        
/*
 * Definitions
 */
#define PRECISION       -18     /* precision (log2 s)  */
#define IPADDR          0       /* any IP address */
#define MODE            0       /* any NTP mode */
#define KEYID           0       /* any key identifier */
        
/*
 * main() - main program
 */
int
main()
{
        struct p *p;            /* peer structure pointer */
        struct r *r;            /* receive packet pointer */
        
/*
 * main() - main program
 */
int
main()
{
        struct p *p;            /* peer structure pointer */
        struct r *r;            /* receive packet pointer */
        
        /*
         * Read command line options and initialize system variables.
         * The reference implementation measures the precision specific
         * to each machine by measuring the clock increments to read the
         * system clock.
         */
        memset(&s, sizeof(s), 0);
        s.leap = NOSYNC;
        s.stratum = MAXSTRAT;
        s.poll = MINPOLL;
        s.precision = PRECISION;
        s.p = NULL;
        
        /*
         * Read command line options and initialize system variables.
         * The reference implementation measures the precision specific
         * to each machine by measuring the clock increments to read the
         * system clock.
         */
        memset(&s, sizeof(s), 0);
        s.leap = NOSYNC;
        s.stratum = MAXSTRAT;
        s.poll = MINPOLL;
        s.precision = PRECISION;
        s.p = NULL;
        
        /*
         * Initialize local clock variables
         */
        memset(&c, sizeof(c), 0);
        if (/* frequency file */ 0) {
                c.freq = /* freq */ 0;
                rstclock(FSET, 0, 0);
        } else {
                rstclock(NSET, 0, 0);
        }
        c.jitter = LOG2D(s.precision);
        
        /*
         * Initialize local clock variables
         */
        memset(&c, sizeof(c), 0);
        if (/* frequency file */ 0) {
                c.freq = /* freq */ 0;
                rstclock(FSET, 0, 0);
        } else {
                rstclock(NSET, 0, 0);
        }
        c.jitter = LOG2D(s.precision);
        
        /*
         * Read the configuration file and mobilize persistent
         * associations with specified addresses, version, mode, key ID,
         * and flags.
         */
        while (/* mobilize configurated associations */ 0) {
                p = mobilize(IPADDR, IPADDR, VERSION, MODE, KEYID,
                    P_FLAGS);
        }
        
        /*
         * Read the configuration file and mobilize persistent
         * associations with specified addresses, version, mode, key ID,
         * and flags.
         */
        while (/* mobilize configurated associations */ 0) {
                p = mobilize(IPADDR, IPADDR, VERSION, MODE, KEYID,
                    P_FLAGS);
        }
        
        /*
         * Start the system timer, which ticks once per second.  Then,
         * read packets as they arrive, strike receive timestamp, and
         * call the receive() routine.
         */
        while (0) {
                r = recv_packet();
                r->dst = get_time();
                receive(r);
        }
        
        /*
         * Start the system timer, which ticks once per second.  Then,
         * read packets as they arrive, strike receive timestamp, and
         * call the receive() routine.
         */
        while (0) {
                r = recv_packet();
                r->dst = get_time();
                receive(r);
        }
        
        return(0);
}
        
        return(0);
}
        
/*
 * mobilize() - mobilize and initialize an association
 */
struct p
*mobilize(
        ipaddr  srcaddr,        /* IP source address */
        ipaddr  dstaddr,        /* IP destination address */
        int     version,        /* version */
        int     mode,           /* host mode */
        int     keyid,          /* key identifier */
        int     flags           /* peer flags */
        )
{
        struct p *p;            /* peer process pointer */
        
/*
 * mobilize() - mobilize and initialize an association
 */
struct p
*mobilize(
        ipaddr  srcaddr,        /* IP source address */
        ipaddr  dstaddr,        /* IP destination address */
        int     version,        /* version */
        int     mode,           /* host mode */
        int     keyid,          /* key identifier */
        int     flags           /* peer flags */
        )
{
        struct p *p;            /* peer process pointer */
        
        /*
         * Allocate and initialize association memory
         */
        p = malloc(sizeof(struct p));
        p->srcaddr = srcaddr;
        p->dstaddr = dstaddr;
        p->version = version;
        p->hmode = mode;
        p->keyid = keyid;
        p->hpoll = MINPOLL;
        clear(p, X_INIT);
        p->flags = flags;
        return (p);
}
        
        /*
         * Allocate and initialize association memory
         */
        p = malloc(sizeof(struct p));
        p->srcaddr = srcaddr;
        p->dstaddr = dstaddr;
        p->version = version;
        p->hmode = mode;
        p->keyid = keyid;
        p->hpoll = MINPOLL;
        clear(p, X_INIT);
        p->flags = flags;
        return (p);
}
        
/*
 * find_assoc() - find a matching association
 */
struct p                        /* peer structure pointer or NULL */
*find_assoc(
        struct r *r             /* receive packet pointer */
        )
{
        struct p *p;            /* dummy peer structure pointer */
        
/*
 * find_assoc() - find a matching association
 */
struct p                        /* peer structure pointer or NULL */
*find_assoc(
        struct r *r             /* receive packet pointer */
        )
{
        struct p *p;            /* dummy peer structure pointer */
        
        /*
         * Search association table for matching source
         * address, source port and mode.
         */
        while (/* all associations */ 0) {
                if (r->srcaddr == p->srcaddr && r->mode == p->hmode)
                        return(p);
        }
        
        /*
         * Search association table for matching source
         * address, source port and mode.
         */
        while (/* all associations */ 0) {
                if (r->srcaddr == p->srcaddr && r->mode == p->hmode)
                        return(p);
        }
        
        return (NULL);
}
        
        return (NULL);
}
        
/*
 * md5() - compute message digest
 */
digest
md5(
       int     keyid           /* key identifier */
       )
{
       /*
        * Compute a keyed cryptographic message digest.  The key
        * identifier is associated with a key in the local key cache.
        * The key is prepended to the packet header and extension fields
        * and the result hashed by the MD5 algorithm as described in
        * RFC 1321.  Return a MAC consisting of the 32-bit key ID
        * concatenated with the 128-bit digest.
        */
       return (/* MD5 digest */ 0);
}
        
/*
 * md5() - compute message digest
 */
digest
md5(
       int     keyid           /* key identifier */
       )
{
       /*
        * Compute a keyed cryptographic message digest.  The key
        * identifier is associated with a key in the local key cache.
        * The key is prepended to the packet header and extension fields
        * and the result hashed by the MD5 algorithm as described in
        * RFC 1321.  Return a MAC consisting of the 32-bit key ID
        * concatenated with the 128-bit digest.
        */
       return (/* MD5 digest */ 0);
}
        
A.3. Kernel Input/Output Interface
A.3. 内核输入/输出接口
   /*
    * Kernel interface to transmit and receive packets.  Details are
    * deliberately vague and depend on the operating system.
    *
    * recv_packet - receive packet from network
    */
   struct r                        /* receive packet pointer*/
   *recv_packet() {
           return (/* receive packet r */ 0);
   }
        
   /*
    * Kernel interface to transmit and receive packets.  Details are
    * deliberately vague and depend on the operating system.
    *
    * recv_packet - receive packet from network
    */
   struct r                        /* receive packet pointer*/
   *recv_packet() {
           return (/* receive packet r */ 0);
   }
        
   /*
    * xmit_packet - transmit packet to network
    */
   void
   xmit_packet(
           struct x *x             /* transmit packet pointer */
           )
   {
           /* send packet x */
   }
        
   /*
    * xmit_packet - transmit packet to network
    */
   void
   xmit_packet(
           struct x *x             /* transmit packet pointer */
           )
   {
           /* send packet x */
   }
        
A.4. Kernel System Clock Interface
A.4. 内核系统时钟接口
/*
 * System clock utility functions
 *
 * There are three time formats: native (Unix), NTP, and floating
 * double.  The get_time() routine returns the time in NTP long format.
 * The Unix routines expect arguments as a structure of two signed
 * 32-bit words in seconds and microseconds (timeval) or nanoseconds
 * (timespec).  The step_time() and adjust_time() routines expect signed
 * arguments in floating double.  The simplified code shown here is for
 * illustration only and has not been verified.
 */
#define JAN_1970        2208988800UL /* 1970 - 1900 in seconds */
        
/*
 * System clock utility functions
 *
 * There are three time formats: native (Unix), NTP, and floating
 * double.  The get_time() routine returns the time in NTP long format.
 * The Unix routines expect arguments as a structure of two signed
 * 32-bit words in seconds and microseconds (timeval) or nanoseconds
 * (timespec).  The step_time() and adjust_time() routines expect signed
 * arguments in floating double.  The simplified code shown here is for
 * illustration only and has not been verified.
 */
#define JAN_1970        2208988800UL /* 1970 - 1900 in seconds */
        
/*
 * get_time - read system time and convert to NTP format
 */
tstamp
get_time()
{
        struct timeval unix_time;
        
/*
 * get_time - read system time and convert to NTP format
 */
tstamp
get_time()
{
        struct timeval unix_time;
        
        /*
         * There are only two calls on this routine in the program.  One
         * when a packet arrives from the network and the other when a
         * packet is placed on the send queue.  Call the kernel time of
         * day routine (such as gettimeofday()) and convert to NTP
         * format.
         */
        gettimeofday(&unix_time, NULL);
        return (U2LFP(unix_time));
}
        
        /*
         * There are only two calls on this routine in the program.  One
         * when a packet arrives from the network and the other when a
         * packet is placed on the send queue.  Call the kernel time of
         * day routine (such as gettimeofday()) and convert to NTP
         * format.
         */
        gettimeofday(&unix_time, NULL);
        return (U2LFP(unix_time));
}
        
/*
 * step_time() - step system time to given offset value
 */
void
step_time(
        double  offset          /* clock offset */
        )
{
        struct timeval unix_time;
        tstamp  ntp_time;
        
/*
 * step_time() - step system time to given offset value
 */
void
step_time(
        double  offset          /* clock offset */
        )
{
        struct timeval unix_time;
        tstamp  ntp_time;
        
        /*
         * Convert from double to native format (signed) and add to the
         * current time.  Note the addition is done in native format to
         * avoid overflow or loss of precision.
         */
        gettimeofday(&unix_time, NULL);
        ntp_time = D2LFP(offset) + U2LFP(unix_time);
        unix_time.tv_sec = ntp_time >> 32;
        unix_time.tv_usec = (long)(((ntp_time - unix_time.tv_sec) <<
            32) / FRAC * 1e6);
        settimeofday(&unix_time, NULL);
}
        
        /*
         * Convert from double to native format (signed) and add to the
         * current time.  Note the addition is done in native format to
         * avoid overflow or loss of precision.
         */
        gettimeofday(&unix_time, NULL);
        ntp_time = D2LFP(offset) + U2LFP(unix_time);
        unix_time.tv_sec = ntp_time >> 32;
        unix_time.tv_usec = (long)(((ntp_time - unix_time.tv_sec) <<
            32) / FRAC * 1e6);
        settimeofday(&unix_time, NULL);
}
        
/*
 * adjust_time() - slew system clock to given offset value
 */
void
adjust_time(
        double  offset          /* clock offset */
        )
{
        struct timeval unix_time;
        tstamp  ntp_time;
        
/*
 * adjust_time() - slew system clock to given offset value
 */
void
adjust_time(
        double  offset          /* clock offset */
        )
{
        struct timeval unix_time;
        tstamp  ntp_time;
        
        /*
         * Convert from double to native format (signed) and add to the
         * current time.
         */
        ntp_time = D2LFP(offset);
        unix_time.tv_sec = ntp_time >> 32;
        unix_time.tv_usec = (long)(((ntp_time - unix_time.tv_sec) <<
            32) / FRAC * 1e6);
        adjtime(&unix_time, NULL);
}
        
        /*
         * Convert from double to native format (signed) and add to the
         * current time.
         */
        ntp_time = D2LFP(offset);
        unix_time.tv_sec = ntp_time >> 32;
        unix_time.tv_usec = (long)(((ntp_time - unix_time.tv_sec) <<
            32) / FRAC * 1e6);
        adjtime(&unix_time, NULL);
}
        
A.5. Peer Process
A.5. 对等进程
   /*
    * A crypto-NAK packet includes the NTP header followed by a MAC
    * consisting only of the key identifier with value zero.  It tells
    * the receiver that a prior request could not be properly
    * authenticated, but the NTP header fields are correct.
    *
    * A kiss-o'-death packet is an NTP header with leap 0x3 (NOSYNC) and
    * stratum 16 (MAXSTRAT).  It tells the receiver that something
    * drastic has happened, as revealed by the kiss code in the refid
    * field.  The NTP header fields may or may not be correct.
    */
   /*
    * Peer process parameters and constants
    */
   #define SGATE           3       /* spike gate (clock filter */
   #define BDELAY          .004    /* broadcast delay (s) */
        
   /*
    * A crypto-NAK packet includes the NTP header followed by a MAC
    * consisting only of the key identifier with value zero.  It tells
    * the receiver that a prior request could not be properly
    * authenticated, but the NTP header fields are correct.
    *
    * A kiss-o'-death packet is an NTP header with leap 0x3 (NOSYNC) and
    * stratum 16 (MAXSTRAT).  It tells the receiver that something
    * drastic has happened, as revealed by the kiss code in the refid
    * field.  The NTP header fields may or may not be correct.
    */
   /*
    * Peer process parameters and constants
    */
   #define SGATE           3       /* spike gate (clock filter */
   #define BDELAY          .004    /* broadcast delay (s) */
        
   /*
    * Dispatch codes
    */
   #define ERR             -1      /* error */
   #define DSCRD           0       /* discard packet */
   #define PROC            1       /* process packet */
   #define BCST            2       /* broadcast packet */
   #define FXMIT           3       /* client packet */
   #define MANY            4       /* manycast packet */
   #define NEWPS           5       /* new symmetric passive client */
   #define NEWBC           6       /* new broadcast client */
        
   /*
    * Dispatch codes
    */
   #define ERR             -1      /* error */
   #define DSCRD           0       /* discard packet */
   #define PROC            1       /* process packet */
   #define BCST            2       /* broadcast packet */
   #define FXMIT           3       /* client packet */
   #define MANY            4       /* manycast packet */
   #define NEWPS           5       /* new symmetric passive client */
   #define NEWBC           6       /* new broadcast client */
        
   /*
    * Dispatch matrix
    *              active  passv  client server bcast */
   int table[7][5] = {
   /* nopeer  */   { NEWPS, DSCRD, FXMIT, MANY, NEWBC },
   /* active  */   { PROC,  PROC,  DSCRD, DSCRD, DSCRD },
   /* passv   */   { PROC,  ERR,   DSCRD, DSCRD, DSCRD },
   /* client  */   { DSCRD, DSCRD, DSCRD, PROC,  DSCRD },
   /* server  */   { DSCRD, DSCRD, DSCRD, DSCRD, DSCRD },
   /* bcast   */   { DSCRD, DSCRD, DSCRD, DSCRD, DSCRD },
   /* bclient */   { DSCRD, DSCRD, DSCRD, DSCRD, PROC}
   };
        
   /*
    * Dispatch matrix
    *              active  passv  client server bcast */
   int table[7][5] = {
   /* nopeer  */   { NEWPS, DSCRD, FXMIT, MANY, NEWBC },
   /* active  */   { PROC,  PROC,  DSCRD, DSCRD, DSCRD },
   /* passv   */   { PROC,  ERR,   DSCRD, DSCRD, DSCRD },
   /* client  */   { DSCRD, DSCRD, DSCRD, PROC,  DSCRD },
   /* server  */   { DSCRD, DSCRD, DSCRD, DSCRD, DSCRD },
   /* bcast   */   { DSCRD, DSCRD, DSCRD, DSCRD, DSCRD },
   /* bclient */   { DSCRD, DSCRD, DSCRD, DSCRD, PROC}
   };
        
   /*
    * Miscellaneous macroni
    *
    * This macro defines the authentication state.  If x is 0,
    * authentication is optional; otherwise, it is required.
    */
   #define AUTH(x, y)      ((x) ? (y) == A_OK : (y) == A_OK || \
                               (y) == A_NONE)
        
   /*
    * Miscellaneous macroni
    *
    * This macro defines the authentication state.  If x is 0,
    * authentication is optional; otherwise, it is required.
    */
   #define AUTH(x, y)      ((x) ? (y) == A_OK : (y) == A_OK || \
                               (y) == A_NONE)
        
   /*
    * These are used by the clear() routine
    */
   #define BEGIN_CLEAR(p)  ((char *)&((p)->begin_clear))
   #define END_CLEAR(p)    ((char *)&((p)->end_clear))
   #define LEN_CLEAR       (END_CLEAR((struct p *)0) - \
                               BEGIN_CLEAR((struct p *)0))
        
   /*
    * These are used by the clear() routine
    */
   #define BEGIN_CLEAR(p)  ((char *)&((p)->begin_clear))
   #define END_CLEAR(p)    ((char *)&((p)->end_clear))
   #define LEN_CLEAR       (END_CLEAR((struct p *)0) - \
                               BEGIN_CLEAR((struct p *)0))
        
A.5.1. receive()
A.5.1. 接收()
/*
 * receive() - receive packet and decode modes
 */
void
receive(
        struct r *r             /* receive packet pointer */
        )
{
        struct p *p;            /* peer structure pointer */
        int     auth;           /* authentication code */
        int     has_mac;        /* size of MAC */
        int     synch;          /* synchronized switch */
        
/*
 * receive() - receive packet and decode modes
 */
void
receive(
        struct r *r             /* receive packet pointer */
        )
{
        struct p *p;            /* peer structure pointer */
        int     auth;           /* authentication code */
        int     has_mac;        /* size of MAC */
        int     synch;          /* synchronized switch */
        
        /*
         * Check access control lists.  The intent here is to implement
         * a whitelist of those IP addresses specifically accepted
         * and/or a blacklist of those IP addresses specifically
         * rejected.  There could be different lists for authenticated
         * clients and unauthenticated clients.
         */
        if (!access(r))
                return;                 /* access denied */
        
        /*
         * Check access control lists.  The intent here is to implement
         * a whitelist of those IP addresses specifically accepted
         * and/or a blacklist of those IP addresses specifically
         * rejected.  There could be different lists for authenticated
         * clients and unauthenticated clients.
         */
        if (!access(r))
                return;                 /* access denied */
        
        /*
         * The version must not be in the future.  Format checks include
         * packet length, MAC length and extension field lengths, if
         * present.
         */
        
        /*
         * The version must not be in the future.  Format checks include
         * packet length, MAC length and extension field lengths, if
         * present.
         */
        
        if (r->version > VERSION /* or format error */)
                return;                 /* format error */
        
        if (r->version > VERSION /* or format error */)
                return;                 /* format error */
        
        /*
         * Authentication is conditioned by two switches that can be
         * specified on a per-client basis.
         *
         * P_NOPEER     do not mobilize an association unless
         *              authenticated.
         * P_NOTRUST    do not allow access unless authenticated
         *              (implies P_NOPEER).
         *
         * There are four outcomes:
         *
         * A_NONE       the packet has no MAC.
         * A_OK         the packet has a MAC and authentication
         *               succeeds.
         * A_ERROR      the packet has a MAC and authentication fails.
         * A_CRYPTO     crypto-NAK.  The MAC has four octets only.
         *
         * Note: The AUTH (x, y) macro is used to filter outcomes.  If x
         * is zero, acceptable outcomes of y are NONE and OK.  If x is
         * one, the only acceptable outcome of y is OK.
         */
        
        /*
         * Authentication is conditioned by two switches that can be
         * specified on a per-client basis.
         *
         * P_NOPEER     do not mobilize an association unless
         *              authenticated.
         * P_NOTRUST    do not allow access unless authenticated
         *              (implies P_NOPEER).
         *
         * There are four outcomes:
         *
         * A_NONE       the packet has no MAC.
         * A_OK         the packet has a MAC and authentication
         *               succeeds.
         * A_ERROR      the packet has a MAC and authentication fails.
         * A_CRYPTO     crypto-NAK.  The MAC has four octets only.
         *
         * Note: The AUTH (x, y) macro is used to filter outcomes.  If x
         * is zero, acceptable outcomes of y are NONE and OK.  If x is
         * one, the only acceptable outcome of y is OK.
         */
        
        has_mac = /* length of MAC field */ 0;
        if (has_mac == 0) {
                auth = A_NONE;          /* not required */
        } else if (has_mac == 4) {
                auth = A_CRYPTO;       /* crypto-NAK */
        } else {
                if (r->mac != md5(r->keyid))
                        auth = A_ERROR; /* auth error */
                else
                        auth = A_OK;    /* auth OK */
        }
        
        has_mac = /* length of MAC field */ 0;
        if (has_mac == 0) {
                auth = A_NONE;          /* not required */
        } else if (has_mac == 4) {
                auth = A_CRYPTO;       /* crypto-NAK */
        } else {
                if (r->mac != md5(r->keyid))
                        auth = A_ERROR; /* auth error */
                else
                        auth = A_OK;    /* auth OK */
        }
        
        /*
         * Find association and dispatch code.  If there is no
         * association to match, the value of p->hmode is assumed NULL.
         */
        p = find_assoc(r);
        switch(table[(unsigned int)(p->hmode)][(unsigned int)(r->mode)])
        {
        
        /*
         * Find association and dispatch code.  If there is no
         * association to match, the value of p->hmode is assumed NULL.
         */
        p = find_assoc(r);
        switch(table[(unsigned int)(p->hmode)][(unsigned int)(r->mode)])
        {
        
        /*
         * Client packet and no association.  Send server reply without
         * saving state.
         */
        case FXMIT:
        
        /*
         * Client packet and no association.  Send server reply without
         * saving state.
         */
        case FXMIT:
        
                /*
                 * If unicast destination address, send server packet.
                 * If authentication fails, send a crypto-NAK packet.
                 */
        
                /*
                 * If unicast destination address, send server packet.
                 * If authentication fails, send a crypto-NAK packet.
                 */
        
                /* not multicast dstaddr */
                if (0) {
                        if (AUTH(p->flags & P_NOTRUST, auth))
                                fast_xmit(r, M_SERV, auth);
                        else if (auth == A_ERROR)
                                fast_xmit(r, M_SERV, A_CRYPTO);
                        return;         /* M_SERV packet sent */
                }
        
                /* not multicast dstaddr */
                if (0) {
                        if (AUTH(p->flags & P_NOTRUST, auth))
                                fast_xmit(r, M_SERV, auth);
                        else if (auth == A_ERROR)
                                fast_xmit(r, M_SERV, A_CRYPTO);
                        return;         /* M_SERV packet sent */
                }
        
                /*
                 * This must be manycast.  Do not respond if we are not
                 * synchronized or if our stratum is above the
                 * manycaster.
                 */
                if (s.leap == NOSYNC || s.stratum > r->stratum)
                        return;
        
                /*
                 * This must be manycast.  Do not respond if we are not
                 * synchronized or if our stratum is above the
                 * manycaster.
                 */
                if (s.leap == NOSYNC || s.stratum > r->stratum)
                        return;
        
                /*
                 * Respond only if authentication is OK.  Note that the
                 * unicast address is used, not the multicast.
                 */
                if (AUTH(p->flags & P_NOTRUST, auth))
                        fast_xmit(r, M_SERV, auth);
                return;
        
                /*
                 * Respond only if authentication is OK.  Note that the
                 * unicast address is used, not the multicast.
                 */
                if (AUTH(p->flags & P_NOTRUST, auth))
                        fast_xmit(r, M_SERV, auth);
                return;
        
        /*
         * New manycast client ephemeral association.  It is mobilized
         * in the same version as in the packet.  If authentication
         * fails, ignore the packet.  Verify the server packet by
         * comparing the r->org timestamp in the packet with the p->xmt
         * timestamp in the multicast client association.  If they
         * match, the server packet is authentic.  Details omitted.
         */
        
        /*
         * New manycast client ephemeral association.  It is mobilized
         * in the same version as in the packet.  If authentication
         * fails, ignore the packet.  Verify the server packet by
         * comparing the r->org timestamp in the packet with the p->xmt
         * timestamp in the multicast client association.  If they
         * match, the server packet is authentic.  Details omitted.
         */
        
        case MANY:
                if (!AUTH(p->flags & (P_NOTRUST | P_NOPEER), auth))
                        return;         /* authentication error */
        
        case MANY:
                if (!AUTH(p->flags & (P_NOTRUST | P_NOPEER), auth))
                        return;         /* authentication error */
        
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_CLNT,
                    r->keyid, P_EPHEM);
                break;
        
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_CLNT,
                    r->keyid, P_EPHEM);
                break;
        
       /*
        * New symmetric passive association.  It is mobilized in the
        * same version as in the packet.  If authentication fails,
        * send a crypto-NAK packet.  If restrict no-moblize, send a
        * symmetric active packet instead.
        */
        case NEWPS:
                if (!AUTH(p->flags & P_NOTRUST, auth)) {
                        if (auth == A_ERROR)
                                fast_xmit(r, M_SACT, A_CRYPTO);
                        return;         /* crypto-NAK packet sent */
                }
                if (!AUTH(p->flags & P_NOPEER, auth)) {
                        fast_xmit(r, M_SACT, auth);
                        return;         /* M_SACT packet sent */
                }
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_PASV,
                    r->keyid, P_EPHEM);
                break;
        
       /*
        * New symmetric passive association.  It is mobilized in the
        * same version as in the packet.  If authentication fails,
        * send a crypto-NAK packet.  If restrict no-moblize, send a
        * symmetric active packet instead.
        */
        case NEWPS:
                if (!AUTH(p->flags & P_NOTRUST, auth)) {
                        if (auth == A_ERROR)
                                fast_xmit(r, M_SACT, A_CRYPTO);
                        return;         /* crypto-NAK packet sent */
                }
                if (!AUTH(p->flags & P_NOPEER, auth)) {
                        fast_xmit(r, M_SACT, auth);
                        return;         /* M_SACT packet sent */
                }
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_PASV,
                    r->keyid, P_EPHEM);
                break;
        
        /*
         * New broadcast client association.  It is mobilized in the
         * same version as in the packet.  If authentication fails,
         * ignore the packet.  Note this code does not support the
         * initial volley feature in the reference implementation.
         */
        case NEWBC:
                if (!AUTH(p->flags & (P_NOTRUST | P_NOPEER), auth))
                        return;         /* authentication error */
        
        /*
         * New broadcast client association.  It is mobilized in the
         * same version as in the packet.  If authentication fails,
         * ignore the packet.  Note this code does not support the
         * initial volley feature in the reference implementation.
         */
        case NEWBC:
                if (!AUTH(p->flags & (P_NOTRUST | P_NOPEER), auth))
                        return;         /* authentication error */
        
                if (!(s.flags & S_BCSTENAB))
                        return;         /* broadcast not enabled */
        
                if (!(s.flags & S_BCSTENAB))
                        return;         /* broadcast not enabled */
        
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_BCLN,
                    r->keyid, P_EPHEM);
                break;                  /* processing continues */
        
                p = mobilize(r->srcaddr, r->dstaddr, r->version, M_BCLN,
                    r->keyid, P_EPHEM);
                break;                  /* processing continues */
        
        /*
         * Process packet.  Placeholdler only.
         */
        case PROC:
                break;                  /* processing continues */
        
        /*
         * Process packet.  Placeholdler only.
         */
        case PROC:
                break;                  /* processing continues */
        
        /*
         * Invalid mode combination.  We get here only in case of
         * ephemeral associations, so the correct action is simply to
         * toss it.
         */
        case ERR:
                clear(p, X_ERROR);
                return;                 /* invalid mode combination */
        
        /*
         * Invalid mode combination.  We get here only in case of
         * ephemeral associations, so the correct action is simply to
         * toss it.
         */
        case ERR:
                clear(p, X_ERROR);
                return;                 /* invalid mode combination */
        
        /*
         * No match; just discard the packet.
         */
        case DSCRD:
                return;                 /* orphan abandoned */
        }
        
        /*
         * No match; just discard the packet.
         */
        case DSCRD:
                return;                 /* orphan abandoned */
        }
        
        /*
         * Next comes a rigorous schedule of timestamp checking.  If the
         * transmit timestamp is zero, the server is horribly broken.
         */
        if (r->xmt == 0)
                return;                 /* invalid timestamp */
        
        /*
         * Next comes a rigorous schedule of timestamp checking.  If the
         * transmit timestamp is zero, the server is horribly broken.
         */
        if (r->xmt == 0)
                return;                 /* invalid timestamp */
        
        /*
         * If the transmit timestamp duplicates a previous one, the
         * packet is a replay.
         */
        if (r->xmt == p->xmt)
                return;                 /* duplicate packet */
        
        /*
         * If the transmit timestamp duplicates a previous one, the
         * packet is a replay.
         */
        if (r->xmt == p->xmt)
                return;                 /* duplicate packet */
        
        /*
         * If this is a broadcast mode packet, skip further checking.
         * If the origin timestamp is zero, the sender has not yet heard
         * from us.  Otherwise, if the origin timestamp does not match
         * the transmit timestamp, the packet is bogus.
         */
        
        /*
         * If this is a broadcast mode packet, skip further checking.
         * If the origin timestamp is zero, the sender has not yet heard
         * from us.  Otherwise, if the origin timestamp does not match
         * the transmit timestamp, the packet is bogus.
         */
        
        synch = TRUE;
        if (r->mode != M_BCST) {
                if (r->org == 0)
                        synch = FALSE;  /* unsynchronized */
        
        synch = TRUE;
        if (r->mode != M_BCST) {
                if (r->org == 0)
                        synch = FALSE;  /* unsynchronized */
        
                else if (r->org != p->xmt)
                        synch = FALSE;  /* bogus packet */
        }
        
                else if (r->org != p->xmt)
                        synch = FALSE;  /* bogus packet */
        }
        
        /*
         * Update the origin and destination timestamps.  If
         * unsynchronized or bogus, abandon ship.
         */
        p->org = r->xmt;
        p->rec = r->dst;
        if (!synch)
                return;                 /* unsynch */
        
        /*
         * Update the origin and destination timestamps.  If
         * unsynchronized or bogus, abandon ship.
         */
        p->org = r->xmt;
        p->rec = r->dst;
        if (!synch)
                return;                 /* unsynch */
        
        /*
         * The timestamps are valid and the receive packet matches the
         * last one sent.  If the packet is a crypto-NAK, the server
         * might have just changed keys.  We demobilize the association
         * and wait for better times.
         */
        if (auth == A_CRYPTO) {
                clear(p, X_CRYPTO);
                return;                 /* crypto-NAK */
        }
        
        /*
         * The timestamps are valid and the receive packet matches the
         * last one sent.  If the packet is a crypto-NAK, the server
         * might have just changed keys.  We demobilize the association
         * and wait for better times.
         */
        if (auth == A_CRYPTO) {
                clear(p, X_CRYPTO);
                return;                 /* crypto-NAK */
        }
        
        /*
         * If the association is authenticated, the key ID is nonzero
         * and received packets must be authenticated.  This is designed
         * to avoid a bait-and-switch attack, which was possible in past
         * versions.
         */
        if (!AUTH(p->keyid || (p->flags & P_NOTRUST), auth))
                return;                 /* bad auth */
        
        /*
         * If the association is authenticated, the key ID is nonzero
         * and received packets must be authenticated.  This is designed
         * to avoid a bait-and-switch attack, which was possible in past
         * versions.
         */
        if (!AUTH(p->keyid || (p->flags & P_NOTRUST), auth))
                return;                 /* bad auth */
        
        /*
         * Everything possible has been done to validate the timestamps
         * and prevent bad guys from disrupting the protocol or
         * injecting bogus data.  Earn some revenue.
         */
        packet(p, r);
}
        
        /*
         * Everything possible has been done to validate the timestamps
         * and prevent bad guys from disrupting the protocol or
         * injecting bogus data.  Earn some revenue.
         */
        packet(p, r);
}
        
A.5.1.1. packet()
A.5.1.1. 数据包()
/*
 * packet() - process packet and compute offset, delay, and
 * dispersion.
 */
void
packet(
        struct p *p,            /* peer structure pointer */
        struct r *r             /* receive packet pointer */
        )
{
        double  offset;         /* sample offsset */
        double  delay;          /* sample delay */
        double  disp;           /* sample dispersion */
        
/*
 * packet() - process packet and compute offset, delay, and
 * dispersion.
 */
void
packet(
        struct p *p,            /* peer structure pointer */
        struct r *r             /* receive packet pointer */
        )
{
        double  offset;         /* sample offsset */
        double  delay;          /* sample delay */
        double  disp;           /* sample dispersion */
        
        /*
         * By golly the packet is valid.  Light up the remaining header
         * fields.  Note that we map stratum 0 (unspecified) to MAXSTRAT
         * to make stratum comparisons simpler and to provide a natural
         * interface for radio clock drivers that operate for
         *  convenience at stratum 0.
         */
        p->leap = r->leap;
        if (r->stratum == 0)
                p->stratum = MAXSTRAT;
        else
                p->stratum = r->stratum;
        p->pmode = r->mode;
        p->ppoll = r->poll;
        p->rootdelay = FP2D(r->rootdelay);
        p->rootdisp = FP2D(r->rootdisp);
        p->refid = r->refid;
        p->reftime = r->reftime;
        
        /*
         * By golly the packet is valid.  Light up the remaining header
         * fields.  Note that we map stratum 0 (unspecified) to MAXSTRAT
         * to make stratum comparisons simpler and to provide a natural
         * interface for radio clock drivers that operate for
         *  convenience at stratum 0.
         */
        p->leap = r->leap;
        if (r->stratum == 0)
                p->stratum = MAXSTRAT;
        else
                p->stratum = r->stratum;
        p->pmode = r->mode;
        p->ppoll = r->poll;
        p->rootdelay = FP2D(r->rootdelay);
        p->rootdisp = FP2D(r->rootdisp);
        p->refid = r->refid;
        p->reftime = r->reftime;
        
        /*
         * Verify the server is synchronized with valid stratum and
         * reference time not later than the transmit time.
         */
        
        /*
         * Verify the server is synchronized with valid stratum and
         * reference time not later than the transmit time.
         */
        
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return;                 /* unsynchronized */
        
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return;                 /* unsynchronized */
        
        /*
         * Verify valid root distance.
         */
        if (r->rootdelay / 2 + r->rootdisp >= MAXDISP || p->reftime >
            r->xmt)
                return;                 /* invalid header values */
        
        /*
         * Verify valid root distance.
         */
        if (r->rootdelay / 2 + r->rootdisp >= MAXDISP || p->reftime >
            r->xmt)
                return;                 /* invalid header values */
        
        poll_update(p, p->hpoll);
        p->reach |= 1;
        
        poll_update(p, p->hpoll);
        p->reach |= 1;
        
        /*
         * Calculate offset, delay and dispersion, then pass to the
         * clock filter.  Note carefully the implied processing.  The
         * first-order difference is done directly in 64-bit arithmetic,
         * then the result is converted to floating double.  All further
         * processing is in floating-double arithmetic with rounding
         * done by the hardware.  This is necessary in order to avoid
         * overflow and preserve precision.
         *
         * The delay calculation is a special case.  In cases where the
         * server and client clocks are running at different rates and
         * with very fast networks, the delay can appear negative.  In
         * order to avoid violating the Principle of Least Astonishment,
         * the delay is clamped not less than the system precision.
         */
        if (p->pmode == M_BCST) {
                offset = LFP2D(r->xmt - r->dst);
                delay = BDELAY;
                disp = LOG2D(r->precision) + LOG2D(s.precision) + PHI *
                    2 * BDELAY;
        } else {
                offset = (LFP2D(r->rec - r->org) + LFP2D(r->dst -
                    r->xmt)) / 2;
                delay = max(LFP2D(r->dst - r->org) - LFP2D(r->rec -
                    r->xmt), LOG2D(s.precision));
                disp = LOG2D(r->precision) + LOG2D(s.precision) + PHI *
                    LFP2D(r->dst - r->org);
        }
        clock_filter(p, offset, delay, disp);
}
        
        /*
         * Calculate offset, delay and dispersion, then pass to the
         * clock filter.  Note carefully the implied processing.  The
         * first-order difference is done directly in 64-bit arithmetic,
         * then the result is converted to floating double.  All further
         * processing is in floating-double arithmetic with rounding
         * done by the hardware.  This is necessary in order to avoid
         * overflow and preserve precision.
         *
         * The delay calculation is a special case.  In cases where the
         * server and client clocks are running at different rates and
         * with very fast networks, the delay can appear negative.  In
         * order to avoid violating the Principle of Least Astonishment,
         * the delay is clamped not less than the system precision.
         */
        if (p->pmode == M_BCST) {
                offset = LFP2D(r->xmt - r->dst);
                delay = BDELAY;
                disp = LOG2D(r->precision) + LOG2D(s.precision) + PHI *
                    2 * BDELAY;
        } else {
                offset = (LFP2D(r->rec - r->org) + LFP2D(r->dst -
                    r->xmt)) / 2;
                delay = max(LFP2D(r->dst - r->org) - LFP2D(r->rec -
                    r->xmt), LOG2D(s.precision));
                disp = LOG2D(r->precision) + LOG2D(s.precision) + PHI *
                    LFP2D(r->dst - r->org);
        }
        clock_filter(p, offset, delay, disp);
}
        
A.5.2. clock_filter()
A.5.2. 时钟滤波器()
/*
 * clock_filter(p, offset, delay, dispersion) - select the best from the
 * latest eight delay/offset samples.
 */
void
clock_filter(
        struct p *p,            /* peer structure pointer */
        double  offset,         /* clock offset */
        double  delay,          /* roundtrip delay */
        double  disp            /* dispersion */
        )
{
        struct f f[NSTAGE];     /* sorted list */
        double  dtemp;
        int     i;
        
/*
 * clock_filter(p, offset, delay, dispersion) - select the best from the
 * latest eight delay/offset samples.
 */
void
clock_filter(
        struct p *p,            /* peer structure pointer */
        double  offset,         /* clock offset */
        double  delay,          /* roundtrip delay */
        double  disp            /* dispersion */
        )
{
        struct f f[NSTAGE];     /* sorted list */
        double  dtemp;
        int     i;
        
        /*
         * The clock filter contents consist of eight tuples (offset,
         * delay, dispersion, time).  Shift each tuple to the left,
         * discarding the leftmost one.  As each tuple is shifted,
         * increase the dispersion since the last filter update.  At the
         * same time, copy each tuple to a temporary list.  After this,
         * place the (offset, delay, disp, time) in the vacated
         * rightmost tuple.
         */
        for (i = 1; i < NSTAGE; i++) {
                p->f[i] = p->f[i - 1];
                p->f[i].disp += PHI * (c.t - p->t);
                f[i] = p->f[i];
        }
        p->f[0].t = c.t;
        p->f[0].offset = offset;
        p->f[0].delay = delay;
        p->f[0].disp = disp;
        f[0] = p->f[0];
        
        /*
         * The clock filter contents consist of eight tuples (offset,
         * delay, dispersion, time).  Shift each tuple to the left,
         * discarding the leftmost one.  As each tuple is shifted,
         * increase the dispersion since the last filter update.  At the
         * same time, copy each tuple to a temporary list.  After this,
         * place the (offset, delay, disp, time) in the vacated
         * rightmost tuple.
         */
        for (i = 1; i < NSTAGE; i++) {
                p->f[i] = p->f[i - 1];
                p->f[i].disp += PHI * (c.t - p->t);
                f[i] = p->f[i];
        }
        p->f[0].t = c.t;
        p->f[0].offset = offset;
        p->f[0].delay = delay;
        p->f[0].disp = disp;
        f[0] = p->f[0];
        
        /*
         * Sort the temporary list of tuples by increasing f[].delay.
         * The first entry on the sorted list represents the best
         * sample, but it might be old.
         */
        dtemp = p->offset;
        p->offset = f[0].offset;
        p->delay = f[0].delay;
        for (i = 0; i < NSTAGE; i++) {
                p->disp += f[i].disp / (2 ^ (i + 1));
        
        /*
         * Sort the temporary list of tuples by increasing f[].delay.
         * The first entry on the sorted list represents the best
         * sample, but it might be old.
         */
        dtemp = p->offset;
        p->offset = f[0].offset;
        p->delay = f[0].delay;
        for (i = 0; i < NSTAGE; i++) {
                p->disp += f[i].disp / (2 ^ (i + 1));
        
                p->jitter += SQUARE(f[i].offset - f[0].offset);
        }
        p->jitter = max(SQRT(p->jitter), LOG2D(s.precision));
        
                p->jitter += SQUARE(f[i].offset - f[0].offset);
        }
        p->jitter = max(SQRT(p->jitter), LOG2D(s.precision));
        
        /*
         * Prime directive: use a sample only once and never a sample
         * older than the latest one, but anything goes before first
         * synchronized.
         */
        if (f[0].t - p->t <= 0 && s.leap != NOSYNC)
                return;
        
        /*
         * Prime directive: use a sample only once and never a sample
         * older than the latest one, but anything goes before first
         * synchronized.
         */
        if (f[0].t - p->t <= 0 && s.leap != NOSYNC)
                return;
        
        /*
         * Popcorn spike suppressor.  Compare the difference between the
         * last and current offsets to the current jitter.  If greater
         * than SGATE (3) and if the interval since the last offset is
         * less than twice the system poll interval, dump the spike.
         * Otherwise, and if not in a burst, shake out the truechimers.
         */
        if (fabs(p->offset - dtemp) > SGATE * p->jitter && (f[0].t -
            p->t) < 2 * s.poll)
                return;
        
        /*
         * Popcorn spike suppressor.  Compare the difference between the
         * last and current offsets to the current jitter.  If greater
         * than SGATE (3) and if the interval since the last offset is
         * less than twice the system poll interval, dump the spike.
         * Otherwise, and if not in a burst, shake out the truechimers.
         */
        if (fabs(p->offset - dtemp) > SGATE * p->jitter && (f[0].t -
            p->t) < 2 * s.poll)
                return;
        
        p->t = f[0].t;
        if (p->burst == 0)
                clock_select();
        return;
}
        
        p->t = f[0].t;
        if (p->burst == 0)
                clock_select();
        return;
}
        
/*
 * fit() - test if association p is acceptable for synchronization
 */
int
fit(
        struct p *p             /* peer structure pointer */
        )
{
        /*
         * A stratum error occurs if (1) the server has never been
         * synchronized, (2) the server stratum is invalid.
         */
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return (FALSE);
        
/*
 * fit() - test if association p is acceptable for synchronization
 */
int
fit(
        struct p *p             /* peer structure pointer */
        )
{
        /*
         * A stratum error occurs if (1) the server has never been
         * synchronized, (2) the server stratum is invalid.
         */
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return (FALSE);
        
        /*
         * A distance error occurs if the root distance exceeds the
         * distance threshold plus an increment equal to one poll
         * interval.
         */
        if (root_dist(p) > MAXDIST + PHI * LOG2D(s.poll))
                return (FALSE);
        
        /*
         * A distance error occurs if the root distance exceeds the
         * distance threshold plus an increment equal to one poll
         * interval.
         */
        if (root_dist(p) > MAXDIST + PHI * LOG2D(s.poll))
                return (FALSE);
        
        /*
         * A loop error occurs if the remote peer is synchronized to the
         * local peer or the remote peer is synchronized to the current
         * system peer.  Note this is the behavior for IPv4; for IPv6
         * the MD5 hash is used instead.
         */
        if (p->refid == p->dstaddr || p->refid == s.refid)
                return (FALSE);
        
        /*
         * A loop error occurs if the remote peer is synchronized to the
         * local peer or the remote peer is synchronized to the current
         * system peer.  Note this is the behavior for IPv4; for IPv6
         * the MD5 hash is used instead.
         */
        if (p->refid == p->dstaddr || p->refid == s.refid)
                return (FALSE);
        
        /*
         * An unreachable error occurs if the server is unreachable.
         */
        if (p->reach == 0)
                return (FALSE);
        
        /*
         * An unreachable error occurs if the server is unreachable.
         */
        if (p->reach == 0)
                return (FALSE);
        
        return (TRUE);
}
        
        return (TRUE);
}
        
/*
 * clear() - reinitialize for persistent association, demobilize
 * for ephemeral association.
 */
void
clear(
        struct p *p,            /* peer structure pointer */
        int     kiss            /* kiss code */
        )
{
        int i;
        
/*
 * clear() - reinitialize for persistent association, demobilize
 * for ephemeral association.
 */
void
clear(
        struct p *p,            /* peer structure pointer */
        int     kiss            /* kiss code */
        )
{
        int i;
        
        /*
         * The first thing to do is return all resources to the bank.
         * Typical resources are not detailed here, but they include
         * dynamically allocated structures for keys, certificates, etc.
         * If an ephemeral association and not initialization, return
         * the association memory as well.
         */
        /* return resources */
        if (s.p == p)
                s.p = NULL;
        
        /*
         * The first thing to do is return all resources to the bank.
         * Typical resources are not detailed here, but they include
         * dynamically allocated structures for keys, certificates, etc.
         * If an ephemeral association and not initialization, return
         * the association memory as well.
         */
        /* return resources */
        if (s.p == p)
                s.p = NULL;
        
        if (kiss != X_INIT && (p->flags & P_EPHEM)) {
                free(p);
                return;
        }
        
        if (kiss != X_INIT && (p->flags & P_EPHEM)) {
                free(p);
                return;
        }
        
        /*
         * Initialize the association fields for general reset.
         */
        memset(BEGIN_CLEAR(p), LEN_CLEAR, 0);
        p->leap = NOSYNC;
        p->stratum = MAXSTRAT;
        p->ppoll = MAXPOLL;
        p->hpoll = MINPOLL;
        p->disp = MAXDISP;
        p->jitter = LOG2D(s.precision);
        p->refid = kiss;
        for (i = 0; i < NSTAGE; i++)
                p->f[i].disp = MAXDISP;
        
        /*
         * Initialize the association fields for general reset.
         */
        memset(BEGIN_CLEAR(p), LEN_CLEAR, 0);
        p->leap = NOSYNC;
        p->stratum = MAXSTRAT;
        p->ppoll = MAXPOLL;
        p->hpoll = MINPOLL;
        p->disp = MAXDISP;
        p->jitter = LOG2D(s.precision);
        p->refid = kiss;
        for (i = 0; i < NSTAGE; i++)
                p->f[i].disp = MAXDISP;
        
        /*
         * Randomize the first poll just in case thousands of broadcast
         * clients have just been stirred up after a long absence of the
         * broadcast server.
         */
        p->outdate = p->t = c.t;
        p->nextdate = p->outdate + (random() & ((1 << MINPOLL) - 1));
}
        
        /*
         * Randomize the first poll just in case thousands of broadcast
         * clients have just been stirred up after a long absence of the
         * broadcast server.
         */
        p->outdate = p->t = c.t;
        p->nextdate = p->outdate + (random() & ((1 << MINPOLL) - 1));
}
        
A.5.3. fast_xmit()
A.5.3. fast_xmit()
/*
 * fast_xmit() - transmit a reply packet for receive packet r
 */
void
fast_xmit(
        struct r *r,            /* receive packet pointer */
        int     mode,           /* association mode */
        int     auth            /* authentication code */
        )
{
        struct x x;
        
/*
 * fast_xmit() - transmit a reply packet for receive packet r
 */
void
fast_xmit(
        struct r *r,            /* receive packet pointer */
        int     mode,           /* association mode */
        int     auth            /* authentication code */
        )
{
        struct x x;
        
        /*
         * Initialize header and transmit timestamp.  Note that the
         * transmit version is copied from the receive version.  This is
         * for backward compatibility.
         */
        
        /*
         * Initialize header and transmit timestamp.  Note that the
         * transmit version is copied from the receive version.  This is
         * for backward compatibility.
         */
        
        x.version = r->version;
        x.srcaddr = r->dstaddr;
        x.dstaddr = r->srcaddr;
        x.leap = s.leap;
        x.mode = mode;
        if (s.stratum == MAXSTRAT)
                x.stratum = 0;
        else
                x.stratum = s.stratum;
        x.poll = r->poll;
        x.precision = s.precision;
        x.rootdelay = D2FP(s.rootdelay);
        x.rootdisp = D2FP(s.rootdisp);
        x.refid = s.refid;
        x.reftime = s.reftime;
        x.org = r->xmt;
        x.rec = r->dst;
        x.xmt = get_time();
        
        x.version = r->version;
        x.srcaddr = r->dstaddr;
        x.dstaddr = r->srcaddr;
        x.leap = s.leap;
        x.mode = mode;
        if (s.stratum == MAXSTRAT)
                x.stratum = 0;
        else
                x.stratum = s.stratum;
        x.poll = r->poll;
        x.precision = s.precision;
        x.rootdelay = D2FP(s.rootdelay);
        x.rootdisp = D2FP(s.rootdisp);
        x.refid = s.refid;
        x.reftime = s.reftime;
        x.org = r->xmt;
        x.rec = r->dst;
        x.xmt = get_time();
        
        /*
         * If the authentication code is A.NONE, include only the
         * header; if A.CRYPTO, send a crypto-NAK; if A.OK, send a valid
         * MAC.  Use the key ID in the received packet and the key in
         * the local key cache.
         */
        if (auth != A_NONE) {
                if (auth == A_CRYPTO) {
                        x.keyid = 0;
                } else {
                        x.keyid = r->keyid;
                        x.dgst = md5(x.keyid);
                }
        }
        xmit_packet(&x);
}
        
        /*
         * If the authentication code is A.NONE, include only the
         * header; if A.CRYPTO, send a crypto-NAK; if A.OK, send a valid
         * MAC.  Use the key ID in the received packet and the key in
         * the local key cache.
         */
        if (auth != A_NONE) {
                if (auth == A_CRYPTO) {
                        x.keyid = 0;
                } else {
                        x.keyid = r->keyid;
                        x.dgst = md5(x.keyid);
                }
        }
        xmit_packet(&x);
}
        
A.5.4. access()
A.5.4. 访问权限()
 /*
  * access() - determine access restrictions
  */
 int
 access(
         struct r *r             /* receive packet pointer */
         )
        
 /*
  * access() - determine access restrictions
  */
 int
 access(
         struct r *r             /* receive packet pointer */
         )
        
 {
         /*
          * The access control list is an ordered set of tuples
          * consisting of an address, mask, and restrict word containing
          * defined bits.  The list is searched for the first match on
          * the source address (r->srcaddr) and the associated restrict
          * word is returned.
          */
         return (/* access bits */ 0);
 }
        
 {
         /*
          * The access control list is an ordered set of tuples
          * consisting of an address, mask, and restrict word containing
          * defined bits.  The list is searched for the first match on
          * the source address (r->srcaddr) and the associated restrict
          * word is returned.
          */
         return (/* access bits */ 0);
 }
        
A.5.5. System Process
A.5.5. 系统过程
A.5.5.1. clock_select()
A.5.5.1. 时钟选择()
/*
 * clock_select() - find the best clocks
 */
void
clock_select() {
       struct p *p, *osys;     /* peer structure pointers */
       double  low, high;      /* correctness interval extents */
       int     allow, found, chime; /* used by intersection algorithm */
       int     n, i, j;
        
/*
 * clock_select() - find the best clocks
 */
void
clock_select() {
       struct p *p, *osys;     /* peer structure pointers */
       double  low, high;      /* correctness interval extents */
       int     allow, found, chime; /* used by intersection algorithm */
       int     n, i, j;
        
        /*
         * We first cull the falsetickers from the server population,
         * leaving only the truechimers.  The correctness interval for
         * association p is the interval from offset - root_dist() to
         * offset + root_dist().  The object of the game is to find a
         * majority clique; that is, an intersection of correctness
         * intervals numbering more than half the server population.
         *
         * First, construct the chime list of tuples (p, type, edge) as
         * shown below, then sort the list by edge from lowest to
         * highest.
         */
        osys = s.p;
        s.p = NULL;
        n = 0;
        while (fit(p)) {
                s.m[n].p = p;
                s.m[n].type = +1;
                s.m[n].edge = p->offset + root_dist(p);
                n++;
                s.m[n].p = p;
                s.m[n].type = 0;
                s.m[n].edge = p->offset;
        
        /*
         * We first cull the falsetickers from the server population,
         * leaving only the truechimers.  The correctness interval for
         * association p is the interval from offset - root_dist() to
         * offset + root_dist().  The object of the game is to find a
         * majority clique; that is, an intersection of correctness
         * intervals numbering more than half the server population.
         *
         * First, construct the chime list of tuples (p, type, edge) as
         * shown below, then sort the list by edge from lowest to
         * highest.
         */
        osys = s.p;
        s.p = NULL;
        n = 0;
        while (fit(p)) {
                s.m[n].p = p;
                s.m[n].type = +1;
                s.m[n].edge = p->offset + root_dist(p);
                n++;
                s.m[n].p = p;
                s.m[n].type = 0;
                s.m[n].edge = p->offset;
        
                n++;
                s.m[n].p = p;
                s.m[n].type = -1;
                s.m[n].edge = p->offset - root_dist(p);
                n++;
        }
        
                n++;
                s.m[n].p = p;
                s.m[n].type = -1;
                s.m[n].edge = p->offset - root_dist(p);
                n++;
        }
        
        /*
         * Find the largest contiguous intersection of correctness
         * intervals.  Allow is the number of allowed falsetickers;
         * found is the number of midpoints.  Note that the edge values
         * are limited to the range +-(2 ^ 30) < +-2e9 by the timestamp
         * calculations.
         */
        low = 2e9; high = -2e9;
        for (allow = 0; 2 * allow < n; allow++) {
        
        /*
         * Find the largest contiguous intersection of correctness
         * intervals.  Allow is the number of allowed falsetickers;
         * found is the number of midpoints.  Note that the edge values
         * are limited to the range +-(2 ^ 30) < +-2e9 by the timestamp
         * calculations.
         */
        low = 2e9; high = -2e9;
        for (allow = 0; 2 * allow < n; allow++) {
        
                /*
                 * Scan the chime list from lowest to highest to find
                 * the lower endpoint.
                 */
                found = 0;
                chime = 0;
                for (i = 0; i < n; i++) {
                        chime -= s.m[i].type;
                        if (chime >= n - found) {
                                low = s.m[i].edge;
                                break;
                        }
                        if (s.m[i].type == 0)
                                found++;
                }
        
                /*
                 * Scan the chime list from lowest to highest to find
                 * the lower endpoint.
                 */
                found = 0;
                chime = 0;
                for (i = 0; i < n; i++) {
                        chime -= s.m[i].type;
                        if (chime >= n - found) {
                                low = s.m[i].edge;
                                break;
                        }
                        if (s.m[i].type == 0)
                                found++;
                }
        
                /*
                 * Scan the chime list from highest to lowest to find
                 * the upper endpoint.
                 */
                chime = 0;
                for (i = n - 1; i >= 0; i--) {
                        chime += s.m[i].type;
                        if (chime >= n - found) {
                                high = s.m[i].edge;
                                break;
                        }
                        if (s.m[i].type == 0)
                                found++;
                }
        
                /*
                 * Scan the chime list from highest to lowest to find
                 * the upper endpoint.
                 */
                chime = 0;
                for (i = n - 1; i >= 0; i--) {
                        chime += s.m[i].type;
                        if (chime >= n - found) {
                                high = s.m[i].edge;
                                break;
                        }
                        if (s.m[i].type == 0)
                                found++;
                }
        
                /*
                 * If the number of midpoints is greater than the number
                 * of allowed falsetickers, the intersection contains at
                 * least one truechimer with no midpoint.  If so,
                 * increment the number of allowed falsetickers and go
                 * around again.  If not and the intersection is
                 * non-empty, declare success.
                 */
                if (found > allow)
                        continue;
        
                /*
                 * If the number of midpoints is greater than the number
                 * of allowed falsetickers, the intersection contains at
                 * least one truechimer with no midpoint.  If so,
                 * increment the number of allowed falsetickers and go
                 * around again.  If not and the intersection is
                 * non-empty, declare success.
                 */
                if (found > allow)
                        continue;
        
                if (high > low)
                        break;
        }
        
                if (high > low)
                        break;
        }
        
        /*
         * Clustering algorithm.  Construct a list of survivors (p,
         * metric) from the chime list, where metric is dominated first
         * by stratum and then by root distance.  All other things being
         * equal, this is the order of preference.
         */
        s.n = 0;
        for (i = 0; i < n; i++) {
                if (s.m[i].edge < low || s.m[i].edge > high)
                        continue;
        
        /*
         * Clustering algorithm.  Construct a list of survivors (p,
         * metric) from the chime list, where metric is dominated first
         * by stratum and then by root distance.  All other things being
         * equal, this is the order of preference.
         */
        s.n = 0;
        for (i = 0; i < n; i++) {
                if (s.m[i].edge < low || s.m[i].edge > high)
                        continue;
        
                p = s.m[i].p;
                s.v[n].p = p;
                s.v[n].metric = MAXDIST * p->stratum + root_dist(p);
                s.n++;
        }
        
                p = s.m[i].p;
                s.v[n].p = p;
                s.v[n].metric = MAXDIST * p->stratum + root_dist(p);
                s.n++;
        }
        
        /*
         * There must be at least NSANE survivors to satisfy the
         * correctness assertions.  Ordinarily, the Byzantine criteria
         * require four survivors, but for the demonstration here, one
         * is acceptable.
         */
        if (s.n < NSANE)
                return;
        
        /*
         * There must be at least NSANE survivors to satisfy the
         * correctness assertions.  Ordinarily, the Byzantine criteria
         * require four survivors, but for the demonstration here, one
         * is acceptable.
         */
        if (s.n < NSANE)
                return;
        
        /*
         * For each association p in turn, calculate the selection
         * jitter p->sjitter as the square root of the sum of squares
         * (p->offset - q->offset) over all q associations.  The idea is
         * to repeatedly discard the survivor with maximum selection
         * jitter until a termination condition is met.
         */
        
        /*
         * For each association p in turn, calculate the selection
         * jitter p->sjitter as the square root of the sum of squares
         * (p->offset - q->offset) over all q associations.  The idea is
         * to repeatedly discard the survivor with maximum selection
         * jitter until a termination condition is met.
         */
        
        while (1) {
                struct p *p, *q, *qmax; /* peer structure pointers */
                double  max, min, dtemp;
        
        while (1) {
                struct p *p, *q, *qmax; /* peer structure pointers */
                double  max, min, dtemp;
        
                max = -2e9; min = 2e9;
                for (i = 0; i < s.n; i++) {
                        p = s.v[i].p;
                        if (p->jitter < min)
                                min = p->jitter;
                        dtemp = 0;
                        for (j = 0; j < n; j++) {
                                q = s.v[j].p;
                                dtemp += SQUARE(p->offset - q->offset);
                        }
                        dtemp = SQRT(dtemp);
                        if (dtemp > max) {
                                max = dtemp;
                                qmax = q;
                        }
                }
        
                max = -2e9; min = 2e9;
                for (i = 0; i < s.n; i++) {
                        p = s.v[i].p;
                        if (p->jitter < min)
                                min = p->jitter;
                        dtemp = 0;
                        for (j = 0; j < n; j++) {
                                q = s.v[j].p;
                                dtemp += SQUARE(p->offset - q->offset);
                        }
                        dtemp = SQRT(dtemp);
                        if (dtemp > max) {
                                max = dtemp;
                                qmax = q;
                        }
                }
        
                /*
                 * If the maximum selection jitter is less than the
                 * minimum peer jitter, then tossing out more survivors
                 * will not lower the minimum peer jitter, so we might
                 * as well stop.  To make sure a few survivors are left
                 * for the clustering algorithm to chew on, we also stop
                 * if the number of survivors is less than or equal to
                 * NMIN (3).
                 */
                if (max < min || n <= NMIN)
                        break;
        
                /*
                 * If the maximum selection jitter is less than the
                 * minimum peer jitter, then tossing out more survivors
                 * will not lower the minimum peer jitter, so we might
                 * as well stop.  To make sure a few survivors are left
                 * for the clustering algorithm to chew on, we also stop
                 * if the number of survivors is less than or equal to
                 * NMIN (3).
                 */
                if (max < min || n <= NMIN)
                        break;
        
                /*
                 * Delete survivor qmax from the list and go around
                 * again.
                 */
                s.n--;
        }
        
                /*
                 * Delete survivor qmax from the list and go around
                 * again.
                 */
                s.n--;
        }
        
        /*
         * Pick the best clock.  If the old system peer is on the list
         * and at the same stratum as the first survivor on the list,
         * then don't do a clock hop.  Otherwise, select the first
         * survivor on the list as the new system peer.
         */
        if (osys->stratum == s.v[0].p->stratum)
                s.p = osys;
        
        /*
         * Pick the best clock.  If the old system peer is on the list
         * and at the same stratum as the first survivor on the list,
         * then don't do a clock hop.  Otherwise, select the first
         * survivor on the list as the new system peer.
         */
        if (osys->stratum == s.v[0].p->stratum)
                s.p = osys;
        
        else
                s.p = s.v[0].p;
        clock_update(s.p);
}
        
        else
                s.p = s.v[0].p;
        clock_update(s.p);
}
        
A.5.5.2. root_dist()
A.5.5.2. 根目录区()
/*
 * root_dist() - calculate root distance
 */
double
root_dist(
        struct p *p             /* peer structure pointer */
        )
{
        
/*
 * root_dist() - calculate root distance
 */
double
root_dist(
        struct p *p             /* peer structure pointer */
        )
{
        
        /*
         * The root synchronization distance is the maximum error due to
         * all causes of the local clock relative to the primary server.
         * It is defined as half the total delay plus total dispersion
         * plus peer jitter.
         */
        return (max(MINDISP, p->rootdelay + p->delay) / 2 +
            p->rootdisp + p->disp + PHI * (c.t - p->t) + p->jitter);
}
        
        /*
         * The root synchronization distance is the maximum error due to
         * all causes of the local clock relative to the primary server.
         * It is defined as half the total delay plus total dispersion
         * plus peer jitter.
         */
        return (max(MINDISP, p->rootdelay + p->delay) / 2 +
            p->rootdisp + p->disp + PHI * (c.t - p->t) + p->jitter);
}
        
A.5.5.3. accept()
A.5.5.3. 接受
/*
 * accept() - test if association p is acceptable for synchronization
 */
int
accept(
        struct p *p             /* peer structure pointer */
        )
{
        /*
         * A stratum error occurs if (1) the server has never been
         * synchronized, (2) the server stratum is invalid.
         */
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return (FALSE);
        
/*
 * accept() - test if association p is acceptable for synchronization
 */
int
accept(
        struct p *p             /* peer structure pointer */
        )
{
        /*
         * A stratum error occurs if (1) the server has never been
         * synchronized, (2) the server stratum is invalid.
         */
        if (p->leap == NOSYNC || p->stratum >= MAXSTRAT)
                return (FALSE);
        
        /*
         * A distance error occurs if the root distance exceeds the
         * distance threshold plus an increment equal to one poll
         * interval.
         */
        
        /*
         * A distance error occurs if the root distance exceeds the
         * distance threshold plus an increment equal to one poll
         * interval.
         */
        
        if (root_dist(p) > MAXDIST + PHI * LOG2D(s.poll))
                return (FALSE);
        
        if (root_dist(p) > MAXDIST + PHI * LOG2D(s.poll))
                return (FALSE);
        
        /*
         * A loop error occurs if the remote peer is synchronized to the
         * local peer or the remote peer is synchronized to the current
         * system peer.  Note this is the behavior for IPv4; for IPv6
         * the MD5 hash is used instead.
         */
        if (p->refid == p->dstaddr || p->refid == s.refid)
                return (FALSE);
        
        /*
         * A loop error occurs if the remote peer is synchronized to the
         * local peer or the remote peer is synchronized to the current
         * system peer.  Note this is the behavior for IPv4; for IPv6
         * the MD5 hash is used instead.
         */
        if (p->refid == p->dstaddr || p->refid == s.refid)
                return (FALSE);
        
        /*
         * An unreachable error occurs if the server is unreachable.
         */
        if (p->reach == 0)
                return (FALSE);
        
        /*
         * An unreachable error occurs if the server is unreachable.
         */
        if (p->reach == 0)
                return (FALSE);
        
        return (TRUE);
}
        
        return (TRUE);
}
        
A.5.5.4. clock_update()
A.5.5.4. 时钟更新()
/*
 * clock_update() - update the system clock
 */
void
clock_update(
        struct p *p             /* peer structure pointer */
        )
{
        double dtemp;
        
/*
 * clock_update() - update the system clock
 */
void
clock_update(
        struct p *p             /* peer structure pointer */
        )
{
        double dtemp;
        
        /*
         * If this is an old update, for instance, as the result of a
         * system peer change, avoid it.  We never use an old sample or
         * the same sample twice.
         */
        if (s.t >= p->t)
                return;
        
        /*
         * If this is an old update, for instance, as the result of a
         * system peer change, avoid it.  We never use an old sample or
         * the same sample twice.
         */
        if (s.t >= p->t)
                return;
        
        /*
         * Combine the survivor offsets and update the system clock; the
         * local_clock() routine will tell us the good or bad news.
         */
        s.t = p->t;
        clock_combine();
        switch (local_clock(p, s.offset)) {
        
        /*
         * Combine the survivor offsets and update the system clock; the
         * local_clock() routine will tell us the good or bad news.
         */
        s.t = p->t;
        clock_combine();
        switch (local_clock(p, s.offset)) {
        
        /*
         * The offset is too large and probably bogus.  Complain to the
         * system log and order the operator to set the clock manually
         * within PANIC range.  The reference implementation includes a
         * command line option to disable this check and to change the
         * panic threshold from the default 1000 s as required.
         */
        case PANIC:
                exit (0);
        
        /*
         * The offset is too large and probably bogus.  Complain to the
         * system log and order the operator to set the clock manually
         * within PANIC range.  The reference implementation includes a
         * command line option to disable this check and to change the
         * panic threshold from the default 1000 s as required.
         */
        case PANIC:
                exit (0);
        
        /*
         * The offset is more than the step threshold (0.125 s by
         * default).  After a step, all associations now have
         * inconsistent time values, so they are reset and started
         * fresh.  The step threshold can be changed in the reference
         * implementation in order to lessen the chance the clock might
         * be stepped backwards.  However, there may be serious
         * consequences, as noted in the white papers at the NTP project
         * site.
         */
        case STEP:
                while (/* all associations */ 0)
                        clear(p, X_STEP);
                s.stratum = MAXSTRAT;
                s.poll = MINPOLL;
                break;
        
        /*
         * The offset is more than the step threshold (0.125 s by
         * default).  After a step, all associations now have
         * inconsistent time values, so they are reset and started
         * fresh.  The step threshold can be changed in the reference
         * implementation in order to lessen the chance the clock might
         * be stepped backwards.  However, there may be serious
         * consequences, as noted in the white papers at the NTP project
         * site.
         */
        case STEP:
                while (/* all associations */ 0)
                        clear(p, X_STEP);
                s.stratum = MAXSTRAT;
                s.poll = MINPOLL;
                break;
        
        /*
         * The offset was less than the step threshold, which is the
         * normal case.  Update the system variables from the peer
         * variables.  The lower clamp on the dispersion increase is to
         * avoid timing loops and clockhopping when highly precise
         * sources are in play.  The clamp can be changed from the
         * default .01 s in the reference implementation.
         */
        case SLEW:
                s.leap = p->leap;
                s.stratum = p->stratum + 1;
                s.refid = p->refid;
                s.reftime = p->reftime;
                s.rootdelay = p->rootdelay + p->delay;
                dtemp = SQRT(SQUARE(p->jitter) + SQUARE(s.jitter));
                dtemp += max(p->disp + PHI * (c.t - p->t) +
                    fabs(p->offset), MINDISP);
                s.rootdisp = p->rootdisp + dtemp;
                break;
        
        /*
         * The offset was less than the step threshold, which is the
         * normal case.  Update the system variables from the peer
         * variables.  The lower clamp on the dispersion increase is to
         * avoid timing loops and clockhopping when highly precise
         * sources are in play.  The clamp can be changed from the
         * default .01 s in the reference implementation.
         */
        case SLEW:
                s.leap = p->leap;
                s.stratum = p->stratum + 1;
                s.refid = p->refid;
                s.reftime = p->reftime;
                s.rootdelay = p->rootdelay + p->delay;
                dtemp = SQRT(SQUARE(p->jitter) + SQUARE(s.jitter));
                dtemp += max(p->disp + PHI * (c.t - p->t) +
                    fabs(p->offset), MINDISP);
                s.rootdisp = p->rootdisp + dtemp;
                break;
        
        /*
         * Some samples are discarded while, for instance, a direct
         * frequency measurement is being made.
         */
        case IGNORE:
                break;
        }
}
        
        /*
         * Some samples are discarded while, for instance, a direct
         * frequency measurement is being made.
         */
        case IGNORE:
                break;
        }
}
        
A.5.5.5. clock_combine()
A.5.5.5. 时钟联合收割机()
/*
 * clock_combine() - combine offsets
 */
void
clock_combine()
{
        struct p *p;            /* peer structure pointer */
        double x, y, z, w;
        int     i;
        
/*
 * clock_combine() - combine offsets
 */
void
clock_combine()
{
        struct p *p;            /* peer structure pointer */
        double x, y, z, w;
        int     i;
        
        /*
         * Combine the offsets of the clustering algorithm survivors
         * using a weighted average with weight determined by the root
         * distance.  Compute the selection jitter as the weighted RMS
         * difference between the first survivor and the remaining
         * survivors.  In some cases, the inherent clock jitter can be
         * reduced by not using this algorithm, especially when frequent
         * clockhopping is involved.  The reference implementation can
         * be configured to avoid this algorithm by designating a
         * preferred peer.
         */
        y = z = w = 0;
        for (i = 0; s.v[i].p != NULL; i++) {
                p = s.v[i].p;
                x = root_dist(p);
                y += 1 / x;
                z += p->offset / x;
                w += SQUARE(p->offset - s.v[0].p->offset) / x;
        }
        s.offset = z / y;
        s.jitter = SQRT(w / y);
}
        
        /*
         * Combine the offsets of the clustering algorithm survivors
         * using a weighted average with weight determined by the root
         * distance.  Compute the selection jitter as the weighted RMS
         * difference between the first survivor and the remaining
         * survivors.  In some cases, the inherent clock jitter can be
         * reduced by not using this algorithm, especially when frequent
         * clockhopping is involved.  The reference implementation can
         * be configured to avoid this algorithm by designating a
         * preferred peer.
         */
        y = z = w = 0;
        for (i = 0; s.v[i].p != NULL; i++) {
                p = s.v[i].p;
                x = root_dist(p);
                y += 1 / x;
                z += p->offset / x;
                w += SQUARE(p->offset - s.v[0].p->offset) / x;
        }
        s.offset = z / y;
        s.jitter = SQRT(w / y);
}
        
A.5.5.6. local_clock()
A.5.5.6. 本地时钟()
/*
 * Clock discipline parameters and constants
 */
#define STEPT           .128    /* step threshold (s) */
#define WATCH           900     /* stepout threshold (s) */
#define PANICT          1000    /* panic threshold (s) */
#define PLL             65536   /* PLL loop gain */
#define FLL             MAXPOLL + 1 /* FLL loop gain */
#define AVG             4       /* parameter averaging constant */
#define ALLAN           1500    /* compromise Allan intercept (s) */
#define LIMIT           30      /* poll-adjust threshold */
#define MAXFREQ         500e-6  /* frequency tolerance (500 ppm) */
#define PGATE           4       /* poll-adjust gate */
        
/*
 * Clock discipline parameters and constants
 */
#define STEPT           .128    /* step threshold (s) */
#define WATCH           900     /* stepout threshold (s) */
#define PANICT          1000    /* panic threshold (s) */
#define PLL             65536   /* PLL loop gain */
#define FLL             MAXPOLL + 1 /* FLL loop gain */
#define AVG             4       /* parameter averaging constant */
#define ALLAN           1500    /* compromise Allan intercept (s) */
#define LIMIT           30      /* poll-adjust threshold */
#define MAXFREQ         500e-6  /* frequency tolerance (500 ppm) */
#define PGATE           4       /* poll-adjust gate */
        
/*
 * local_clock() - discipline the local clock
 */
int                             /* return code */
local_clock(
        struct p *p,            /* peer structure pointer */
        double  offset          /* clock offset from combine() */
        )
{
        int     state;          /* clock discipline state */
        double  freq;           /* frequency */
        double  mu;             /* interval since last update */
        int     rval;
        double  etemp, dtemp;
        
/*
 * local_clock() - discipline the local clock
 */
int                             /* return code */
local_clock(
        struct p *p,            /* peer structure pointer */
        double  offset          /* clock offset from combine() */
        )
{
        int     state;          /* clock discipline state */
        double  freq;           /* frequency */
        double  mu;             /* interval since last update */
        int     rval;
        double  etemp, dtemp;
        
        /*
         * If the offset is too large, give up and go home.
         */
        if (fabs(offset) > PANICT)
                return (PANIC);
        
        /*
         * If the offset is too large, give up and go home.
         */
        if (fabs(offset) > PANICT)
                return (PANIC);
        
        /*
         * Clock state machine transition function.  This is where the
         * action is and defines how the system reacts to large time
         * and frequency errors.  There are two main regimes: when the
         * offset exceeds the step threshold and when it does not.
         */
        rval = SLEW;
        mu = p->t - s.t;
        freq = 0;
        if (fabs(offset) > STEPT) {
                switch (c.state) {
        
        /*
         * Clock state machine transition function.  This is where the
         * action is and defines how the system reacts to large time
         * and frequency errors.  There are two main regimes: when the
         * offset exceeds the step threshold and when it does not.
         */
        rval = SLEW;
        mu = p->t - s.t;
        freq = 0;
        if (fabs(offset) > STEPT) {
                switch (c.state) {
        
                /*
                 * In S_SYNC state, we ignore the first outlier and
                 * switch to S_SPIK state.
                 */
                case SYNC:
                        state = SPIK;
                        return (rval);
        
                /*
                 * In S_SYNC state, we ignore the first outlier and
                 * switch to S_SPIK state.
                 */
                case SYNC:
                        state = SPIK;
                        return (rval);
        
                /*
                 * In S_FREQ state, we ignore outliers and inliers.  At
                 * the first outlier after the stepout threshold,
                 * compute the apparent frequency correction and step
                 * the time.
                 */
                case FREQ:
                        if (mu < WATCH)
                                return (IGNORE);
        
                /*
                 * In S_FREQ state, we ignore outliers and inliers.  At
                 * the first outlier after the stepout threshold,
                 * compute the apparent frequency correction and step
                 * the time.
                 */
                case FREQ:
                        if (mu < WATCH)
                                return (IGNORE);
        
                        freq = (offset - c.offset) / mu;
                        /* fall through to S_SPIK */
        
                        freq = (offset - c.offset) / mu;
                        /* fall through to S_SPIK */
        
                /*
                 * In S_SPIK state, we ignore succeeding outliers until
                 * either an inlier is found or the stepout threshold is
                 * exceeded.
                 */
                case SPIK:
                        if (mu < WATCH)
                                return (IGNORE);
        
                /*
                 * In S_SPIK state, we ignore succeeding outliers until
                 * either an inlier is found or the stepout threshold is
                 * exceeded.
                 */
                case SPIK:
                        if (mu < WATCH)
                                return (IGNORE);
        
                        /* fall through to default */
        
                        /* fall through to default */
        
                /*
                 * We get here by default in S_NSET and S_FSET states
                 * and from above in S_FREQ state.  Step the time and
                 * clamp down the poll interval.
                 *
                 * In S_NSET state, an initial frequency correction is
                 * not available, usually because the frequency file has
                 * not yet been written.  Since the time is outside the
                 * capture range, the clock is stepped.  The frequency
                 * will be set directly following the stepout interval.
                 *
                 * In S_FSET state, the initial frequency has been set
                 * from the frequency file.  Since the time is outside
                 * the capture range, the clock is stepped immediately,
                 * rather than after the stepout interval.  Guys get
                 * nervous if it takes 17 minutes to set the clock for
        
                /*
                 * We get here by default in S_NSET and S_FSET states
                 * and from above in S_FREQ state.  Step the time and
                 * clamp down the poll interval.
                 *
                 * In S_NSET state, an initial frequency correction is
                 * not available, usually because the frequency file has
                 * not yet been written.  Since the time is outside the
                 * capture range, the clock is stepped.  The frequency
                 * will be set directly following the stepout interval.
                 *
                 * In S_FSET state, the initial frequency has been set
                 * from the frequency file.  Since the time is outside
                 * the capture range, the clock is stepped immediately,
                 * rather than after the stepout interval.  Guys get
                 * nervous if it takes 17 minutes to set the clock for
        

* the first time. * * In S_SPIK state, the stepout threshold has expired * and the phase is still above the step threshold. * Note that a single spike greater than the step * threshold is always suppressed, even at the longer * poll intervals. */ default:

*第一次。**在S_SPIK状态下,阶跃阈值已过期*且相位仍高于阶跃阈值。*请注意,大于阶跃*阈值的单个峰值始终被抑制,即使在较长的*轮询间隔中也是如此。*/违约:

                        /*
                         * This is the kernel set time function, usually
                         * implemented by the Unix settimeofday() system
                         * call.
                         */
                        step_time(offset);
                        c.count = 0;
                        s.poll = MINPOLL;
                        rval = STEP;
                        if (state == NSET) {
                                rstclock(FREQ, p->t, 0);
                                return (rval);
                        }
                        break;
                }
                rstclock(SYNC, p->t, 0);
        } else {
        
                        /*
                         * This is the kernel set time function, usually
                         * implemented by the Unix settimeofday() system
                         * call.
                         */
                        step_time(offset);
                        c.count = 0;
                        s.poll = MINPOLL;
                        rval = STEP;
                        if (state == NSET) {
                                rstclock(FREQ, p->t, 0);
                                return (rval);
                        }
                        break;
                }
                rstclock(SYNC, p->t, 0);
        } else {
        
                /*
                 * Compute the clock jitter as the RMS of exponentially
                 * weighted offset differences.  This is used by the
                 * poll-adjust code.
                 */
                etemp = SQUARE(c.jitter);
                dtemp = SQUARE(max(fabs(offset - c.last),
                    LOG2D(s.precision)));
                c.jitter = SQRT(etemp + (dtemp - etemp) / AVG);
                switch (c.state) {
        
                /*
                 * Compute the clock jitter as the RMS of exponentially
                 * weighted offset differences.  This is used by the
                 * poll-adjust code.
                 */
                etemp = SQUARE(c.jitter);
                dtemp = SQUARE(max(fabs(offset - c.last),
                    LOG2D(s.precision)));
                c.jitter = SQRT(etemp + (dtemp - etemp) / AVG);
                switch (c.state) {
        
                /*
                 * In S_NSET state, this is the first update received
                 * and the frequency has not been initialized.  The
                 * first thing to do is directly measure the oscillator
                 * frequency.
                 */
                case NSET:
                        rstclock(FREQ, p->t, offset);
                        return (IGNORE);
        
                /*
                 * In S_NSET state, this is the first update received
                 * and the frequency has not been initialized.  The
                 * first thing to do is directly measure the oscillator
                 * frequency.
                 */
                case NSET:
                        rstclock(FREQ, p->t, offset);
                        return (IGNORE);
        
                /*
                 * In S_FSET state, this is the first update and the
                 * frequency has been initialized.  Adjust the phase,
                 * but don't adjust the frequency until the next update.
                 */
                case FSET:
                        rstclock(SYNC, p->t, offset);
                        break;
        
                /*
                 * In S_FSET state, this is the first update and the
                 * frequency has been initialized.  Adjust the phase,
                 * but don't adjust the frequency until the next update.
                 */
                case FSET:
                        rstclock(SYNC, p->t, offset);
                        break;
        
                /*
                 * In S_FREQ state, ignore updates until the stepout
                 * threshold.  After that, correct the phase and
                 * frequency and switch to S_SYNC state.
                 */
                case FREQ:
                        if (c.t - s.t < WATCH)
                                return (IGNORE);
        
                /*
                 * In S_FREQ state, ignore updates until the stepout
                 * threshold.  After that, correct the phase and
                 * frequency and switch to S_SYNC state.
                 */
                case FREQ:
                        if (c.t - s.t < WATCH)
                                return (IGNORE);
        
                        freq = (offset - c.offset) / mu;
                        break;
        
                        freq = (offset - c.offset) / mu;
                        break;
        
                /*
                 * We get here by default in S_SYNC and S_SPIK states.
                 * Here we compute the frequency update due to PLL and
                 * FLL contributions.
                 */
                default:
        
                /*
                 * We get here by default in S_SYNC and S_SPIK states.
                 * Here we compute the frequency update due to PLL and
                 * FLL contributions.
                 */
                default:
        
                        /*
                         * The FLL and PLL frequency gain constants
                         * depending on the poll interval and Allan
                         * intercept.  The FLL is not used below one
                         * half the Allan intercept.  Above that the
                         * loop gain increases in steps to 1 / AVG.
                         */
                        if (LOG2D(s.poll) > ALLAN / 2) {
                                etemp = FLL - s.poll;
                                if (etemp < AVG)
                                        etemp = AVG;
                                freq += (offset - c.offset) / (max(mu,
                                    ALLAN) * etemp);
                        }
        
                        /*
                         * The FLL and PLL frequency gain constants
                         * depending on the poll interval and Allan
                         * intercept.  The FLL is not used below one
                         * half the Allan intercept.  Above that the
                         * loop gain increases in steps to 1 / AVG.
                         */
                        if (LOG2D(s.poll) > ALLAN / 2) {
                                etemp = FLL - s.poll;
                                if (etemp < AVG)
                                        etemp = AVG;
                                freq += (offset - c.offset) / (max(mu,
                                    ALLAN) * etemp);
                        }
        
                        /*
                         * For the PLL the integration interval
                         * (numerator) is the minimum of the update
                         * interval and poll interval.  This allows
                         * oversampling, but not undersampling.
                         */
                        etemp = min(mu, LOG2D(s.poll));
                        dtemp = 4 * PLL * LOG2D(s.poll);
                        freq += offset * etemp / (dtemp * dtemp);
                        rstclock(SYNC, p->t, offset);
                        break;
                }
        }
        
                        /*
                         * For the PLL the integration interval
                         * (numerator) is the minimum of the update
                         * interval and poll interval.  This allows
                         * oversampling, but not undersampling.
                         */
                        etemp = min(mu, LOG2D(s.poll));
                        dtemp = 4 * PLL * LOG2D(s.poll);
                        freq += offset * etemp / (dtemp * dtemp);
                        rstclock(SYNC, p->t, offset);
                        break;
                }
        }
        
        /*
         * Calculate the new frequency and frequency stability (wander).
         * Compute the clock wander as the RMS of exponentially weighted
         * frequency differences.  This is not used directly, but can,
         * along with the jitter, be a highly useful monitoring and
         * debugging tool.
         */
        freq += c.freq;
        c.freq = max(min(MAXFREQ, freq), -MAXFREQ);
        etemp = SQUARE(c.wander);
        dtemp = SQUARE(freq);
        c.wander = SQRT(etemp + (dtemp - etemp) / AVG);
        
        /*
         * Calculate the new frequency and frequency stability (wander).
         * Compute the clock wander as the RMS of exponentially weighted
         * frequency differences.  This is not used directly, but can,
         * along with the jitter, be a highly useful monitoring and
         * debugging tool.
         */
        freq += c.freq;
        c.freq = max(min(MAXFREQ, freq), -MAXFREQ);
        etemp = SQUARE(c.wander);
        dtemp = SQUARE(freq);
        c.wander = SQRT(etemp + (dtemp - etemp) / AVG);
        
        /*
         * Here we adjust the poll interval by comparing the current
         * offset with the clock jitter.  If the offset is less than the
         * clock jitter times a constant, then the averaging interval is
         * increased; otherwise, it is decreased.  A bit of hysteresis
         * helps calm the dance.  Works best using burst mode.
         */
        if (fabs(c.offset) < PGATE * c.jitter) {
                c.count += s.poll;
                if (c.count > LIMIT) {
                        c.count = LIMIT;
                        if (s.poll < MAXPOLL) {
                                c.count = 0;
                                s.poll++;
                        }
                }
        } else {
                c.count -= s.poll << 1;
                if (c.count < -LIMIT) {
                        c.count = -LIMIT;
                        if (s.poll > MINPOLL) {
        
        /*
         * Here we adjust the poll interval by comparing the current
         * offset with the clock jitter.  If the offset is less than the
         * clock jitter times a constant, then the averaging interval is
         * increased; otherwise, it is decreased.  A bit of hysteresis
         * helps calm the dance.  Works best using burst mode.
         */
        if (fabs(c.offset) < PGATE * c.jitter) {
                c.count += s.poll;
                if (c.count > LIMIT) {
                        c.count = LIMIT;
                        if (s.poll < MAXPOLL) {
                                c.count = 0;
                                s.poll++;
                        }
                }
        } else {
                c.count -= s.poll << 1;
                if (c.count < -LIMIT) {
                        c.count = -LIMIT;
                        if (s.poll > MINPOLL) {
        
                                c.count = 0;
                                s.poll--;
                        }
                }
        }
        return (rval);
}
        
                                c.count = 0;
                                s.poll--;
                        }
                }
        }
        return (rval);
}
        
A.5.5.7. rstclock()
A.5.5.7. rstclock()
  /*
   * rstclock() - clock state machine
   */
  void
  rstclock(
          int     state,          /* new state */
          double  offset,         /* new offset */
          double  t               /* new update time */
          )
  {
          /*
           * Enter new state and set state variables.  Note, we use the
           * time of the last clock filter sample, which must be earlier
           * than the current time.
           */
          c.state = state;
          c.last = c.offset = offset;
          s.t = t;
  }
        
  /*
   * rstclock() - clock state machine
   */
  void
  rstclock(
          int     state,          /* new state */
          double  offset,         /* new offset */
          double  t               /* new update time */
          )
  {
          /*
           * Enter new state and set state variables.  Note, we use the
           * time of the last clock filter sample, which must be earlier
           * than the current time.
           */
          c.state = state;
          c.last = c.offset = offset;
          s.t = t;
  }
        
A.5.6. Clock Adjust Process
A.5.6. 时钟调整过程
A.5.6.1. clock_adjust()
A.5.6.1. 时钟调整
 /*
  * clock_adjust() - runs at one-second intervals
  */
 void
 clock_adjust() {
         double  dtemp;
        
 /*
  * clock_adjust() - runs at one-second intervals
  */
 void
 clock_adjust() {
         double  dtemp;
        
         /*
          * Update the process time c.t.  Also increase the dispersion
          * since the last update.  In contrast to NTPv3, NTPv4 does not
          * declare unsynchronized after one day, since the dispersion
          * threshold serves this function.  When the dispersion exceeds
          * MAXDIST (1 s), the server is considered unfit for
          * synchronization.
        
         /*
          * Update the process time c.t.  Also increase the dispersion
          * since the last update.  In contrast to NTPv3, NTPv4 does not
          * declare unsynchronized after one day, since the dispersion
          * threshold serves this function.  When the dispersion exceeds
          * MAXDIST (1 s), the server is considered unfit for
          * synchronization.
        
          */
         c.t++;
         s.rootdisp += PHI;
        
          */
         c.t++;
         s.rootdisp += PHI;
        
         /*
          * Implement the phase and frequency adjustments.  The gain
          * factor (denominator) is not allowed to increase beyond the
          * Allan intercept.  It doesn't make sense to average phase
          * noise beyond this point and it helps to damp residual offset
          * at the longer poll intervals.
          */
         dtemp = c.offset / (PLL * min(LOG2D(s.poll), ALLAN));
         c.offset -= dtemp;
        
         /*
          * Implement the phase and frequency adjustments.  The gain
          * factor (denominator) is not allowed to increase beyond the
          * Allan intercept.  It doesn't make sense to average phase
          * noise beyond this point and it helps to damp residual offset
          * at the longer poll intervals.
          */
         dtemp = c.offset / (PLL * min(LOG2D(s.poll), ALLAN));
         c.offset -= dtemp;
        
         /*
          * This is the kernel adjust time function, usually implemented
          * by the Unix adjtime() system call.
          */
         adjust_time(c.freq + dtemp);
        
         /*
          * This is the kernel adjust time function, usually implemented
          * by the Unix adjtime() system call.
          */
         adjust_time(c.freq + dtemp);
        
         /*
          * Peer timer.  Call the poll() routine when the poll timer
          * expires.
          */
         while (/* all associations */ 0) {
                 struct p *p;    /* dummy peer structure pointer */
        
         /*
          * Peer timer.  Call the poll() routine when the poll timer
          * expires.
          */
         while (/* all associations */ 0) {
                 struct p *p;    /* dummy peer structure pointer */
        
                 if (c.t >= p->nextdate)
                         poll(p);
         }
        
                 if (c.t >= p->nextdate)
                         poll(p);
         }
        
         /*
          * Once per hour, write the clock frequency to a file.
          */
         /*
          * if (c.t % 3600 == 3599)
          *   write c.freq to file
          */
 }
        
         /*
          * Once per hour, write the clock frequency to a file.
          */
         /*
          * if (c.t % 3600 == 3599)
          *   write c.freq to file
          */
 }
        
A.5.7. Poll Process
A.5.7. 投票过程
   /*
    * Poll process parameters and constants
    */
   #define UNREACH         12      /* unreach counter threshold */
   #define BCOUNT          8       /* packets in a burst */
   #define BTIME           2       /* burst interval (s) */
        
   /*
    * Poll process parameters and constants
    */
   #define UNREACH         12      /* unreach counter threshold */
   #define BCOUNT          8       /* packets in a burst */
   #define BTIME           2       /* burst interval (s) */
        
A.5.7.1. poll()
A.5.7.1. 投票()
/*
 * poll() - determine when to send a packet for association p->
 */
void
poll(
        struct p *p             /* peer structure pointer */
        )
{
        int     hpoll;
        int     oreach;
        
/*
 * poll() - determine when to send a packet for association p->
 */
void
poll(
        struct p *p             /* peer structure pointer */
        )
{
        int     hpoll;
        int     oreach;
        
        /*
         * This routine is called when the current time c.t catches up
         * to the next poll time p->nextdate.  The value p->outdate is
         * the last time this routine was executed.  The poll_update()
         * routine determines the next execution time p->nextdate.
         *
         * If broadcasting, just do it, but only if we are synchronized.
         */
        hpoll = p->hpoll;
        if (p->hmode == M_BCST) {
                p->outdate = c.t;
                if (s.p != NULL)
                        peer_xmit(p);
                poll_update(p, hpoll);
                return;
        }
        
        /*
         * This routine is called when the current time c.t catches up
         * to the next poll time p->nextdate.  The value p->outdate is
         * the last time this routine was executed.  The poll_update()
         * routine determines the next execution time p->nextdate.
         *
         * If broadcasting, just do it, but only if we are synchronized.
         */
        hpoll = p->hpoll;
        if (p->hmode == M_BCST) {
                p->outdate = c.t;
                if (s.p != NULL)
                        peer_xmit(p);
                poll_update(p, hpoll);
                return;
        }
        
        /*
         * If manycasting, start with ttl = 1.  The ttl is increased by
         * one for each poll until MAXCLOCK servers have been found or
         * ttl reaches TTLMAX.  If reaching MAXCLOCK, stop polling until
         * the number of servers falls below MINCLOCK, then start all
         * over.
         */
        if (p->hmode == M_CLNT && p->flags & P_MANY) {
                p->outdate = c.t;
                if (p->unreach > BEACON) {
                        p->unreach = 0;
                        p->ttl = 1;
                        peer_xmit(p);
                } else if (s.n < MINCLOCK) {
                        if (p->ttl < TTLMAX)
                                p->ttl++;
                        peer_xmit(p);
                }
        
        /*
         * If manycasting, start with ttl = 1.  The ttl is increased by
         * one for each poll until MAXCLOCK servers have been found or
         * ttl reaches TTLMAX.  If reaching MAXCLOCK, stop polling until
         * the number of servers falls below MINCLOCK, then start all
         * over.
         */
        if (p->hmode == M_CLNT && p->flags & P_MANY) {
                p->outdate = c.t;
                if (p->unreach > BEACON) {
                        p->unreach = 0;
                        p->ttl = 1;
                        peer_xmit(p);
                } else if (s.n < MINCLOCK) {
                        if (p->ttl < TTLMAX)
                                p->ttl++;
                        peer_xmit(p);
                }
        
                p->unreach++;
                poll_update(p, hpoll);
                return;
        }
        if (p->burst == 0) {
        
                p->unreach++;
                poll_update(p, hpoll);
                return;
        }
        if (p->burst == 0) {
        
                /*
                 * We are not in a burst.  Shift the reachability
                 * register to the left.  Hopefully, some time before
                 * the next poll a packet will arrive and set the
                 * rightmost bit.
                 */
                oreach = p->reach;
                p->outdate = c.t;
                p->reach = p->reach << 1;
                if (!(p->reach & 0x7))
                        clock_filter(p, 0, 0, MAXDISP);
                if (!p->reach) {
        
                /*
                 * We are not in a burst.  Shift the reachability
                 * register to the left.  Hopefully, some time before
                 * the next poll a packet will arrive and set the
                 * rightmost bit.
                 */
                oreach = p->reach;
                p->outdate = c.t;
                p->reach = p->reach << 1;
                if (!(p->reach & 0x7))
                        clock_filter(p, 0, 0, MAXDISP);
                if (!p->reach) {
        
                        /*
                         * The server is unreachable, so bump the
                         * unreach counter.  If the unreach threshold
                         * has been reached, double the poll interval
                         * to minimize wasted network traffic.  Send a
                         * burst only if enabled and the unreach
                         * threshold has not been reached.
                         */
                        if (p->flags & P_IBURST && p->unreach == 0) {
                                p->burst = BCOUNT;
                        } else if (p->unreach < UNREACH)
                                p->unreach++;
                        else
                                hpoll++;
                        p->unreach++;
                } else {
        
                        /*
                         * The server is unreachable, so bump the
                         * unreach counter.  If the unreach threshold
                         * has been reached, double the poll interval
                         * to minimize wasted network traffic.  Send a
                         * burst only if enabled and the unreach
                         * threshold has not been reached.
                         */
                        if (p->flags & P_IBURST && p->unreach == 0) {
                                p->burst = BCOUNT;
                        } else if (p->unreach < UNREACH)
                                p->unreach++;
                        else
                                hpoll++;
                        p->unreach++;
                } else {
        
                        /*
                         * The server is reachable.  Set the poll
                         * interval to the system poll interval.  Send a
                         * burst only if enabled and the peer is fit.
                         */
                        p->unreach = 0;
                        hpoll = s.poll;
                        if (p->flags & P_BURST && fit(p))
                                p->burst = BCOUNT;
                }
        } else {
        
                        /*
                         * The server is reachable.  Set the poll
                         * interval to the system poll interval.  Send a
                         * burst only if enabled and the peer is fit.
                         */
                        p->unreach = 0;
                        hpoll = s.poll;
                        if (p->flags & P_BURST && fit(p))
                                p->burst = BCOUNT;
                }
        } else {
        
                /*
                 * If in a burst, count it down.  When the reply comes
                 * back the clock_filter() routine will call
                 * clock_select() to process the results of the burst.
                 */
                p->burst--;
        }
        /*
         * Do not transmit if in broadcast client mode.
         */
        if (p->hmode != M_BCLN)
                peer_xmit(p);
        poll_update(p, hpoll);
}
        
                /*
                 * If in a burst, count it down.  When the reply comes
                 * back the clock_filter() routine will call
                 * clock_select() to process the results of the burst.
                 */
                p->burst--;
        }
        /*
         * Do not transmit if in broadcast client mode.
         */
        if (p->hmode != M_BCLN)
                peer_xmit(p);
        poll_update(p, hpoll);
}
        
A.5.7.2. poll_update()
A.5.7.2. 轮询_更新()
/*
 * poll_update() - update the poll interval for association p
 *
 * Note: This routine is called by both the packet() and poll() routine.
 * Since the packet() routine is executed when a network packet arrives
 * and the poll() routine is executed as the result of timeout, a
 * potential race can occur, possibly causing an incorrect interval for
 * the next poll.  This is considered so unlikely as to be negligible.
 */
void
poll_update(
        struct p *p,            /* peer structure pointer */
        int     poll            /* poll interval (log2 s) */
        )
{
        /*
         * This routine is called by both the poll() and packet()
         * routines to determine the next poll time.  If within a burst
         * the poll interval is two seconds.  Otherwise, it is the
         * minimum of the host poll interval and peer poll interval, but
         * not greater than MAXPOLL and not less than MINPOLL.  The
         * design ensures that a longer interval can be preempted by a
         * shorter one if required for rapid response.
         */
        p->hpoll = max(min(MAXPOLL, poll), MINPOLL);
        if (p->burst > 0) {
                if (p->nextdate != c.t)
                        return;
                else
                        p->nextdate += BTIME;
        } else {
        
/*
 * poll_update() - update the poll interval for association p
 *
 * Note: This routine is called by both the packet() and poll() routine.
 * Since the packet() routine is executed when a network packet arrives
 * and the poll() routine is executed as the result of timeout, a
 * potential race can occur, possibly causing an incorrect interval for
 * the next poll.  This is considered so unlikely as to be negligible.
 */
void
poll_update(
        struct p *p,            /* peer structure pointer */
        int     poll            /* poll interval (log2 s) */
        )
{
        /*
         * This routine is called by both the poll() and packet()
         * routines to determine the next poll time.  If within a burst
         * the poll interval is two seconds.  Otherwise, it is the
         * minimum of the host poll interval and peer poll interval, but
         * not greater than MAXPOLL and not less than MINPOLL.  The
         * design ensures that a longer interval can be preempted by a
         * shorter one if required for rapid response.
         */
        p->hpoll = max(min(MAXPOLL, poll), MINPOLL);
        if (p->burst > 0) {
                if (p->nextdate != c.t)
                        return;
                else
                        p->nextdate += BTIME;
        } else {
        
                /*
                 * While not shown here, the reference implementation
                 * randomizes the poll interval by a small factor.
                 */
                p->nextdate = p->outdate + (1 << max(min(p->ppoll,
                    p->hpoll), MINPOLL));
        }
        
                /*
                 * While not shown here, the reference implementation
                 * randomizes the poll interval by a small factor.
                 */
                p->nextdate = p->outdate + (1 << max(min(p->ppoll,
                    p->hpoll), MINPOLL));
        }
        
        /*
         * It might happen that the due time has already passed.  If so,
         * make it one second in the future.
         */
        if (p->nextdate <= c.t)
                p->nextdate = c.t + 1;
}
        
        /*
         * It might happen that the due time has already passed.  If so,
         * make it one second in the future.
         */
        if (p->nextdate <= c.t)
                p->nextdate = c.t + 1;
}
        
A.5.7.3. peer_xmit()
A.5.7.3. peer_xmit()
/*
 * transmit() - transmit a packet for association p
 */
void
peer_xmit(
        struct p *p             /* peer structure pointer */
        )
{
        struct x x;             /* transmit packet */
        
/*
 * transmit() - transmit a packet for association p
 */
void
peer_xmit(
        struct p *p             /* peer structure pointer */
        )
{
        struct x x;             /* transmit packet */
        
        /*
         * Initialize header and transmit timestamp
         */
        x.srcaddr = p->dstaddr;
        x.dstaddr = p->srcaddr;
        x.leap = s.leap;
        x.version = p->version;
        x.mode = p->hmode;
        if (s.stratum == MAXSTRAT)
                x.stratum = 0;
        else
                x.stratum = s.stratum;
        x.poll = p->hpoll;
        x.precision = s.precision;
        x.rootdelay = D2FP(s.rootdelay);
        x.rootdisp = D2FP(s.rootdisp);
        x.refid = s.refid;
        x.reftime = s.reftime;
        x.org = p->org;
        x.rec = p->rec;
        
        /*
         * Initialize header and transmit timestamp
         */
        x.srcaddr = p->dstaddr;
        x.dstaddr = p->srcaddr;
        x.leap = s.leap;
        x.version = p->version;
        x.mode = p->hmode;
        if (s.stratum == MAXSTRAT)
                x.stratum = 0;
        else
                x.stratum = s.stratum;
        x.poll = p->hpoll;
        x.precision = s.precision;
        x.rootdelay = D2FP(s.rootdelay);
        x.rootdisp = D2FP(s.rootdisp);
        x.refid = s.refid;
        x.reftime = s.reftime;
        x.org = p->org;
        x.rec = p->rec;
        
        x.xmt = get_time();
        p->xmt = x.xmt;
        
        x.xmt = get_time();
        p->xmt = x.xmt;
        
        /*
         * If the key ID is nonzero, send a valid MAC using the key ID
         * of the association and the key in the local key cache.  If
         * something breaks, like a missing trusted key, don't send the
         * packet; just reset the association and stop until the problem
         * is fixed.
         */
        if (p->keyid)
                if (/* p->keyid invalid */ 0) {
                        clear(p, X_NKEY);
                        return;
                }
                x.dgst = md5(p->keyid);
        xmit_packet(&x);
}
        
        /*
         * If the key ID is nonzero, send a valid MAC using the key ID
         * of the association and the key in the local key cache.  If
         * something breaks, like a missing trusted key, don't send the
         * packet; just reset the association and stop until the problem
         * is fixed.
         */
        if (p->keyid)
                if (/* p->keyid invalid */ 0) {
                        clear(p, X_NKEY);
                        return;
                }
                x.dgst = md5(p->keyid);
        xmit_packet(&x);
}
        

Authors' Addresses

作者地址

Dr. David L. Mills University of Delaware Newark, DE 19716 US

戴维·L·米尔斯·德拉瓦大学NeWalk,DE 19716美国

   Phone: +1 302 831 8247
   EMail: mills@udel.edu
        
   Phone: +1 302 831 8247
   EMail: mills@udel.edu
        

Jim Martin (editor) Internet Systems Consortium 950 Charter Street Redwood City, CA 94063 US

吉姆·马丁(编辑)美国加利福尼亚州红木市查特街950号互联网系统联盟,邮编94063

   Phone: +1 650 423 1378
   EMail: jrmii@isc.org
        
   Phone: +1 650 423 1378
   EMail: jrmii@isc.org
        

Jack Burbank The Johns Hopkins University Applied Physics Laboratory 11100 Johns Hopkins Road Laurel, MD 20723-6099 US

杰克·伯班克美国马里兰州劳雷尔市约翰·霍普金斯路11100号约翰·霍普金斯大学应用物理实验室20723-6099

   Phone: +1 443 778 7127
   EMail: jack.burbank@jhuapl.edu
        
   Phone: +1 443 778 7127
   EMail: jack.burbank@jhuapl.edu
        

William Kasch The Johns Hopkins University Applied Physics Laboratory 11100 Johns Hopkins Road Laurel, MD 20723-6099 US

威廉·卡什美国马里兰州劳雷尔市约翰·霍普金斯路11100号约翰·霍普金斯大学应用物理实验室20723-6099

   Phone: +1 443 778 7463
   EMail: william.kasch@jhuapl.edu
        
   Phone: +1 443 778 7463
   EMail: william.kasch@jhuapl.edu