IEEE 1588标准文档与linuxptp代码的映射

学习IEEE 1588-2008标准文档的一种方法是找一个PTP开源项目,通过阅读源码的方式加深对标准的理解。linuxptp是Linux系统上最流行的PTP开源实现,本文对linuxptp进行代码分析,并给出代码和IEEE 1588-2008文档的映射。

1、linuxptp项目简介

linuxptp提供了以下工具实现时钟同步:

  • ptp4l:遵循IEEE 1588-2008标准文档规范,实现了BC(Boundary Clock)、OC(Ordinary Clock)和TC(Transparent Clock);
  • phc2sys:用于同步当前设备上的两个时钟,譬如让System Clock与PHC (PTP Hardware Clock)保持同步;
  • pcm:在ptp4l运行期间对其进行配置。

ptp4l支持SW(软件时间戳)与HW(硬件时间戳)。如果采用HW,ptp4l实现PHC与BMC(Best Master Clock)的同步,而phc2sys实现System Clock与PHC的同步;如果采用SW,ptp4l实现System Clock与BMC的同步,不需要运行phc2sys。

2、ptp4l

图1 ptp4l模型

2.1 数据结构

//clock.c
struct clock {
  struct defaultDS dds;         //描述当前clock的属性
  int time_source;              //grandmaster时钟的时间来源(如GPS),该值仅用于信息展示,不参于BMC算法计算,参考《IEEE 1588-2008V2》7.6.2.6小节
  struct currentDS cur;         //时钟同步相关的属性
  struct parent_ds dad;         //parent与grandmaster时钟的属性
  struct timePropertiesDS tds;  //timescale的属性
  LIST_HEAD(ports_head, port) ports; //port列表
}
//ddt.h
struct ClockQuality {
  UInteger8     clockClass;                //如果值<=127,那么该clock不能成为slave,参考《IEEE 1588-2008V2》7.6.2.4小节
  Enumeration8  clockAccuracy;             //标记时钟的精度,用于执行BMC算法,参考《IEEE 1588-2008V2》7.6.2.5小节
  UInteger16    offsetScaledLogVariance;   //时钟的稳定性,用于执行BMC算法,参考《IEEE 1588-2008V2》7.6.3.2小节
};
//ds.h
struct defaultDS {
    UInteger8            flags;                //twoStepFlag和slaveOnly的标记位
    UInteger16           numberPorts;          //当前设备的port个数,参考《IEEE 1588-2008V2》7.6.2.7小节
    UInteger8            priority1;            //用于执行BMC算法,数值越小优先级越高,参考《IEEE 1588-2008V2》7.6.2.2小节
    struct ClockQuality clockQuality;
    UInteger8            priority2;            //类似priority1,参考《IEEE 1588-2008V2》7.6.2.3小节
    struct ClockIdentity clockIdentity;        //时钟id,参考《IEEE 1588-2008V2》7.6.2.1小节
    UInteger8            domainNumber;         //ptp域id,参考《IEEE 1588-2008V2》7.1小节
  };

struct currentDS {
  UInteger16   stepsRemoved;            //当前时钟到gransmaster时钟的距离,参考《IEEE 1588-2008V2》8.2.2.2小节
  TimeInterval offsetFromMaster;        //当前时钟与master时钟的时间差值,参考《IEEE 1588-2008V2》8.2.2.3小节
  TimeInterval meanPathDelay;           //当前时钟到master时钟的传播耗时,meanPathDelay的计算可参考《IEEE 1588-2008V2》11.3与11.4小节
}

struct parentDs {
    struct PortIdentity  parentPortIdentity;
    UInteger8            parentStats;                            //TRUE代表observedParentOffsetScaledLogVariance和observedParentClockPhaseChangeRate是有效值,参考《IEEE 1588-2008V2》7.6.4.2小节
    UInteger16           observedParentOffsetScaledLogVariance;  //对parent时钟的精度的估计,参考《IEEE 1588-2008V2》7.6.4.3小节
    Integer32            observedParentClockPhaseChangeRate;     //对parent时钟的相位变化频率的估计,参考《IEEE 1588-2008V2》7.6.4.4小节
    UInteger8            grandmasterPriority1;                   //grandmaster时钟的priority1属性,参考《IEEE 1588-2008V2》8.2.3.8小节
    struct ClockQuality  grandmasterClockQuality;                //grandmaster时钟的ClockQuality属性,参考《IEEE 1588-2008V2》8.2.3.7小节
    UInteger8            grandmasterPriority2;                   //grandmaster时钟的priority2属性,参考《IEEE 1588-2008V2》8.2.3.9小节
    struct ClockIdentity grandmasterIdentity;                    //grandmaster时钟的id,参考《IEEE 1588-2008V2》8.2.3.6小节
  };

struct timePropertiesDS {
  Integer16    currentUtcOffset;  //TAI与UTC时间的差值,单位为秒,参考《IEEE 1588-2008V2》8.2.4.2小节
  UInteger8    flags;             //currentUtcOffsetValid、leap59、leap61、timeTraceable、frequencyTraceable和ptpTimescale标记位,参考《IEEE 1588-2008V2》8.2.4.3-8.2.4.8小节
  Enumeration8 timeSource;        //grandmaster时钟的时间来源(如GPS),参考《IEEE 1588-2008V2》8.2.4.9小节
} ;

struct portDS {
  struct PortIdentity portIdentity;
  Enumeration8        portState;                //port的当前状态,可选值见下面Table 1
  Integer8            logMinDelayReqInterval;   //DelayReq的超时间隔的最小值,参考《IEEE 1588-2008V2》8.2.5.3.2小节
  TimeInterval        peerMeanPathDelay;        //delayMechanism为P2P模式时,当前port到相邻port的传播耗时;如果delayMechanism为E2E模式,该值应该为0,参考《IEEE 1588-2008V2》8.2.5.3.3小节
  Integer8            logAnnounceInterval;      //发送Announce消息的间隔,参考《IEEE 1588-2008V2》8.2.5.4.1小节
  UInteger8           announceReceiptTimeout;   //接收Announce消息超时时长,参考《IEEE 1588-2008V2》8.2.5.4.2小节
  Integer8            logSyncInterval;          //发送Sync消息的间隔,参考《IEEE 1588-2008V2》8.2.5.4.1小节
  Enumeration8        delayMechanism;           //测量传播耗时的机制,可选值为E2E和P2P,参考《IEEE 1588-2008V2》8.2.5.4.4小节
  Integer8            logMinPdelayReqInterval;  //接收PdelayReq消息超时时长,参考《IEEE 1588-2008V2》8.2.5.4.2小节8.2.5.4.5小节
  UInteger8           versionNumber;            //PTP版本
} ;
Table1 PTP state

2.2 工作流程

图2 ptp4l工作流程

初始化本地时钟流程:

struct clock *clock_create()
{
  if (phc_index >= 0) 
    c->clkid = phc_open(phc);    //打开phc API,用于操作PTP硬件时钟,参考上面图1
  
  /*servo根据offsetFromMaster调整本地时钟的频率。
   由于延迟波动,计算出来的offsetFromMaster与实际值会有偏差,servo算法用于减少这种偏差,默认servo算法为PI Controller*/
  c->servo = servo_create(); 

  c->tsproc = tsproc_create();   //创建filter对offset进行平滑,可选filter有移动平均滤波器、移动中值滤波器等,参考上面图1

  STAILQ_FOREACH(iface, &config->interfaces, list) 
    clock_add_port(c, phc_device, phc_index, timestamping, iface);  //创建ports

  LIST_FOREACH(p, &c->ports, list) 
    port_dispatch(p, EV_INITIALIZE);  //初始化port
}

void port_dispatch(struct port *p)
{
  p->dispatch(p);    //如果是BC(Boundary Clock)或OC(Ordinary Clock),执行bc_dispatch
}

void bc_dispatch(struct port *p)
{
  port_state_update(p);      //事件导致state machine更新状态,见下面图3
  port_e2e_transition(p);    //根据当前状态,更新定时器,参考《IEEE 1588-2008V2》7.7小节
}

int port_state_update(struct port *p)
{
  if (PS_INITIALIZING == next) 
    port_initialize(p);
}

int port_initialize(struct port *p)
{
  transport_open();          //如果是udp port,执行udp_open
  port_set_announce_tmo();   //设置接收announce message超时定时器,参考《IEEE 1588-2008V2》7.7.3.1小节
}

int udp_open()
{
  efd = open_socket(name, mcast_addr, EVENT_PORT, ttl);      //打开event interface句柄,见上图1
  gfd = open_socket(name, mcast_addr, GENERAL_PORT, ttl);    //打开general interface句柄,见上图1

  sk_timestamping_init(efd, interface_label(iface), ts_type, TRANS_UDP_IPV4,
                 interface_get_vclock(iface));                //通知内核对event message要打时间戳

  /*设置event message和general message的dscp优先级,《IEEE 1588-2008V2》并未规定dscp,但AES67与RAVENNA标准对此有要求*/
  sk_set_priority(efd, AF_INET, event_dscp);
  sk_set_priority(gfd, AF_INET, general_dscp);
}

处理事件流程:

int clock_poll(struct clock *c)
{
  clock_check_pollfd(c);    //更新c->pollfd队列,将各个port的socket和timer文件描述符都加入到队列中
  poll(c->pollfd);
  LIST_FOREACH(p, &c->ports, list) {
    event = port_event(p);    //处理事件
    port_dispatch(p, event);  //根据state machine更新状态,更新定时器
  }

  handle_state_decision_event(c);  //执行bmc计算
}

enum fsm_event port_event(struct port *p)
{
    return p->event(p);  //如果是BC(Boundary Clock)或OC(Ordinary Clock),执行bc_event
}

enum fsm_event bc_event(struct port *p)
{
  switch (fd_index) {
    case FD_ANNOUNCE_TIMER:
    case FD_SYNC_RX_TIMER:
      //定时器超时,失去同步
      fc_clear(p->best);          //移除master的announce message
      port_set_announce_tmo(p);   //重置接收announce message超时定时器,参考《IEEE 1588-2008V2》7.7.3.1小节
      delay_req_prune(p);         //移除过期的delay req message
      return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES;  //事件导致state machine更新状态,见下面图3

    case FD_DELAY_TIMER:
      port_set_delay_tmo(p);      //更新发送Delay_Req message或Pdelay_Req message的定时器,参考《IEEE 1588-2008V2》7.7.2.4小节和7.7.2.5小节
      delay_req_prune(p);         //移除过期的delay req message
      port_delay_request(p);      //如果是e2e机制,发送Delay_Req message;如果是p2p机制,发送Pdelay_Req message
      return EV_NONE;

    case FD_QUALIFICATION_TIMER:
      return EV_QUALIFICATION_TIMEOUT_EXPIRES;  //在PRE_MASTER等待了足够的时间,状态变为MASTER,见下面图3

    case FD_MANNO_TIMER:
      port_set_manno_tmo(p);      //更新发送Announce message的定时器,参考《IEEE 1588-2008V2》7.7.2.2小节
      port_tx_announce(p);        //发送Announce message
      return EV_NONE;

    case FD_SYNC_TX_TIMER:
      port_set_sync_tx_tmo(p);    //更新发送Sync message的定时器,参考《IEEE 1588-2008V2》7.7.2.3小节
      port_tx_sync(p);            //发送Sync message
      return EV_NONE;

    case FD_RTNL:
      rtnl_link_status();         //监控网卡状态变化
      if (网卡状态变更) 
        return EV_FAULT_DETECTED;
      else
        return EV_NONE;
  }

  transport_recv(p->trp, fd, msg);    //接收message,如果是event message,记录接收时间戳
  switch (msg_type(msg)) {
    case SYNC:
      process_sync(p, msg);           //处理Sync message,处理流程见下面图4,参考《IEEE 1588-2008V2》9.5.4小节
      break;

    case DELAY_REQ:
      process_delay_req(p, msg);      //处理Delay_Req message,处理流程见下面图5,参考《IEEE 1588-2008V2》9.5.6小节
      break;

    case PDELAY_REQ:
      process_pdelay_req(p, msg);     //处理Pdelay_Req message,发送Pdelay_Resp message和Pdelay_Resp_Follow_Up message,参考《IEEE 1588-2008V2》9.5.14和9.5.15小节
      break;

    case PDELAY_RESP:
      process_pdelay_resp(p, msg);    //处理Pdelay_Resp message,如果是one-step模式,计算链路传播耗时,参考《IEEE 1588-2008V2》11.4小节
      break;

    case FOLLOW_UP:
      process_follow_up(p, msg);      //处理Follow_Up message,处理流程见下面图6,参考《IEEE 1588-2008V2》9.5.5小节
      break;

    case DELAY_RESP:
      process_delay_resp(p, msg);     //处理Delay_Resp message,处理流程见下面图7,参考《IEEE 1588-2008V2》9.5.7小节
      break;

    case PDELAY_RESP_FOLLOW_UP:
      process_pdelay_resp_fup(p, msg); //处理Pdelay_Resp_Follow_Up message,计算链路传播耗时,参考《IEEE 1588-2008V2》11.4小节
      break;

    case ANNOUNCE:
      process_announce(p, msg);        //处理Announce message,处理流程见下面图8,参考《IEEE 1588-2008V2》9.5.3小节
      break;

    case SIGNALING:
      process_signaling(p, msg);        //处理Signaling message,参考《IEEE 1588-2008V2》16.1小节
      break;

    case MANAGEMENT:
      clock_manage(p->clock, p, msg);   //处理Management message,参考《IEEE 1588-2008V2》15.3小节
      break;
  }
}


图3 ptp状态机
图4 接收Sync message的逻辑
图5 接收Delay_Req message的逻辑
图6 接收Follow_Up message的逻辑
图7 接收Delay_Resp message的逻辑
图8 接收Announce message的逻辑

BMC计算流程:

//BMC计算流程概述见《IEEE 1588-2008V2》9.3.2.2小节
void handle_state_decision_event(struct clock *c)
{
  LIST_FOREACH(piter, &c->ports, list) {
    fc = port_compute_best(piter);                    //port根据收到的Announce message选出最优的foreign clock
    if (c->dscmp(&fc->dataset, &best->dataset) > 0)   //比较各个port的最优foreign clock,选出全局最优foreign clock,dscmp对比流程见下面图9和图10,参考《IEEE 1588-2008V2》9.3.4小节
      best = fc;
  }

  c->best = best;

  LIST_FOREACH(piter, &c->ports, list)
    bmc_state_decision(c, piter, c->dscmp);           //port根据新选出来的best clock更新各自的状态,更新逻辑见下面图11,参考《IEEE 1588-2008V2》9.3.3小节
}
图9 Data set比较算法
图10 Data set比较算法
图11 bmc state decision算法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 计算机中的 system clock:system clock is maintained by the kern...
    SnC_阅读 2,335评论 0 0
  • IEEE 1588协议简单理解 ​ IEEE 1588 是一个精密时间协议 (PTP),用于同步计算机...
    fafactx阅读 1,659评论 0 0
  • 1、数字音频传输的优点 传统的模拟音频传输存在信号损耗、电磁干扰和接地干扰等问题;而数字音频传输抗干扰能力强,整个...
    myroncml阅读 7,326评论 0 5
  • 关于时间这件小事 频率 带宽与频率与频率相关的另一个参数是数据传输率,也称为"带宽",用于衡量数据通信速度的快慢。...
    胡聿泽阅读 1,082评论 0 0
  • 此recommendation的全名为 PTP telecom profile for phase/time sy...
    SnC_阅读 4,246评论 0 0