IEEE 1588標(biāo)準(zhǔn)文檔與linuxptp代碼的映射

學(xué)習(xí)IEEE 1588-2008標(biāo)準(zhǔn)文檔的一種方法是找一個PTP開源項目分瘦,通過閱讀源碼的方式加深對標(biāo)準(zhǔn)的理解路捧。linuxptp是Linux系統(tǒng)上最流行的PTP開源實現(xiàn)甩苛,本文對linuxptp進(jìn)行代碼分析勿锅,并給出代碼和IEEE 1588-2008文檔的映射早抠。

1腌巾、linuxptp項目簡介

linuxptp提供了以下工具實現(xiàn)時鐘同步:

  • ptp4l:遵循IEEE 1588-2008標(biāo)準(zhǔn)文檔規(guī)范杠袱,實現(xiàn)了BC(Boundary Clock)昵济、OC(Ordinary Clock)和TC(Transparent Clock)智绸;
  • phc2sys:用于同步當(dāng)前設(shè)備上的兩個時鐘,譬如讓System Clock與PHC (PTP Hardware Clock)保持同步访忿;
  • pcm:在ptp4l運行期間對其進(jìn)行配置瞧栗。

ptp4l支持SW(軟件時間戳)與HW(硬件時間戳)。如果采用HW海铆,ptp4l實現(xiàn)PHC與BMC(Best Master Clock)的同步迹恐,而phc2sys實現(xiàn)System Clock與PHC的同步;如果采用SW卧斟,ptp4l實現(xiàn)System Clock與BMC的同步殴边,不需要運行phc2sys。

2珍语、ptp4l

圖1 ptp4l模型

2.1 數(shù)據(jù)結(jié)構(gòu)

//clock.c
struct clock {
  struct defaultDS dds;         //描述當(dāng)前clock的屬性
  int time_source;              //grandmaster時鐘的時間來源(如GPS)锤岸,該值僅用于信息展示,不參于BMC算法計算板乙,參考《IEEE 1588-2008V2》7.6.2.6小節(jié)
  struct currentDS cur;         //時鐘同步相關(guān)的屬性
  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小節(jié)
  Enumeration8  clockAccuracy;             //標(biāo)記時鐘的精度募逞,用于執(zhí)行BMC算法蛋铆,參考《IEEE 1588-2008V2》7.6.2.5小節(jié)
  UInteger16    offsetScaledLogVariance;   //時鐘的穩(wěn)定性,用于執(zhí)行BMC算法放接,參考《IEEE 1588-2008V2》7.6.3.2小節(jié)
};
//ds.h
struct defaultDS {
    UInteger8            flags;                //twoStepFlag和slaveOnly的標(biāo)記位
    UInteger16           numberPorts;          //當(dāng)前設(shè)備的port個數(shù)戒职,參考《IEEE 1588-2008V2》7.6.2.7小節(jié)
    UInteger8            priority1;            //用于執(zhí)行BMC算法,數(shù)值越小優(yōu)先級越高透乾,參考《IEEE 1588-2008V2》7.6.2.2小節(jié)
    struct ClockQuality clockQuality;
    UInteger8            priority2;            //類似priority1,參考《IEEE 1588-2008V2》7.6.2.3小節(jié)
    struct ClockIdentity clockIdentity;        //時鐘id磕秤,參考《IEEE 1588-2008V2》7.6.2.1小節(jié)
    UInteger8            domainNumber;         //ptp域id乳乌,參考《IEEE 1588-2008V2》7.1小節(jié)
  };

struct currentDS {
  UInteger16   stepsRemoved;            //當(dāng)前時鐘到gransmaster時鐘的距離市咆,參考《IEEE 1588-2008V2》8.2.2.2小節(jié)
  TimeInterval offsetFromMaster;        //當(dāng)前時鐘與master時鐘的時間差值,參考《IEEE 1588-2008V2》8.2.2.3小節(jié)
  TimeInterval meanPathDelay;           //當(dāng)前時鐘到master時鐘的傳播耗時磷瘤,meanPathDelay的計算可參考《IEEE 1588-2008V2》11.3與11.4小節(jié)
}

struct parentDs {
    struct PortIdentity  parentPortIdentity;
    UInteger8            parentStats;                            //TRUE代表observedParentOffsetScaledLogVariance和observedParentClockPhaseChangeRate是有效值扳抽,參考《IEEE 1588-2008V2》7.6.4.2小節(jié)
    UInteger16           observedParentOffsetScaledLogVariance;  //對parent時鐘的精度的估計,參考《IEEE 1588-2008V2》7.6.4.3小節(jié)
    Integer32            observedParentClockPhaseChangeRate;     //對parent時鐘的相位變化頻率的估計,參考《IEEE 1588-2008V2》7.6.4.4小節(jié)
    UInteger8            grandmasterPriority1;                   //grandmaster時鐘的priority1屬性,參考《IEEE 1588-2008V2》8.2.3.8小節(jié)
    struct ClockQuality  grandmasterClockQuality;                //grandmaster時鐘的ClockQuality屬性,參考《IEEE 1588-2008V2》8.2.3.7小節(jié)
    UInteger8            grandmasterPriority2;                   //grandmaster時鐘的priority2屬性沧竟,參考《IEEE 1588-2008V2》8.2.3.9小節(jié)
    struct ClockIdentity grandmasterIdentity;                    //grandmaster時鐘的id,參考《IEEE 1588-2008V2》8.2.3.6小節(jié)
  };

struct timePropertiesDS {
  Integer16    currentUtcOffset;  //TAI與UTC時間的差值,單位為秒,參考《IEEE 1588-2008V2》8.2.4.2小節(jié)
  UInteger8    flags;             //currentUtcOffsetValid、leap59、leap61、timeTraceable、frequencyTraceable和ptpTimescale標(biāo)記位流椒,參考《IEEE 1588-2008V2》8.2.4.3-8.2.4.8小節(jié)
  Enumeration8 timeSource;        //grandmaster時鐘的時間來源(如GPS),參考《IEEE 1588-2008V2》8.2.4.9小節(jié)
} ;

struct portDS {
  struct PortIdentity portIdentity;
  Enumeration8        portState;                //port的當(dāng)前狀態(tài)鹉胖,可選值見下面Table 1
  Integer8            logMinDelayReqInterval;   //DelayReq的超時間隔的最小值寂诱,參考《IEEE 1588-2008V2》8.2.5.3.2小節(jié)
  TimeInterval        peerMeanPathDelay;        //delayMechanism為P2P模式時音羞,當(dāng)前port到相鄰port的傳播耗時仓犬;如果delayMechanism為E2E模式,該值應(yīng)該為0舍肠,參考《IEEE 1588-2008V2》8.2.5.3.3小節(jié)
  Integer8            logAnnounceInterval;      //發(fā)送Announce消息的間隔搀继,參考《IEEE 1588-2008V2》8.2.5.4.1小節(jié)
  UInteger8           announceReceiptTimeout;   //接收Announce消息超時時長窘面,參考《IEEE 1588-2008V2》8.2.5.4.2小節(jié)
  Integer8            logSyncInterval;          //發(fā)送Sync消息的間隔,參考《IEEE 1588-2008V2》8.2.5.4.1小節(jié)
  Enumeration8        delayMechanism;           //測量傳播耗時的機制叽躯,可選值為E2E和P2P财边,參考《IEEE 1588-2008V2》8.2.5.4.4小節(jié)
  Integer8            logMinPdelayReqInterval;  //接收PdelayReq消息超時時長,參考《IEEE 1588-2008V2》8.2.5.4.2小節(jié)8.2.5.4.5小節(jié)
  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根據(jù)offsetFromMaster調(diào)整本地時鐘的頻率。
   由于延遲波動黑滴,計算出來的offsetFromMaster與實際值會有偏差憨募,servo算法用于減少這種偏差,默認(rèn)servo算法為PI Controller*/
  c->servo = servo_create(); 

  c->tsproc = tsproc_create();   //創(chuàng)建filter對offset進(jìn)行平滑袁辈,可選filter有移動平均濾波器菜谣、移動中值濾波器等,參考上面圖1

  STAILQ_FOREACH(iface, &config->interfaces, list) 
    clock_add_port(c, phc_device, phc_index, timestamping, iface);  //創(chuàng)建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)晚缩,執(zhí)行bc_dispatch
}

void bc_dispatch(struct port *p)
{
  port_state_update(p);      //事件導(dǎo)致state machine更新狀態(tài)尾膊,見下面圖3
  port_e2e_transition(p);    //根據(jù)當(dāng)前狀態(tài),更新定時器荞彼,參考《IEEE 1588-2008V2》7.7小節(jié)
}

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

int port_initialize(struct port *p)
{
  transport_open();          //如果是udp port冈敛,執(zhí)行udp_open
  port_set_announce_tmo();   //設(shè)置接收announce message超時定時器,參考《IEEE 1588-2008V2》7.7.3.1小節(jié)
}

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));                //通知內(nèi)核對event message要打時間戳

  /*設(shè)置event message和general message的dscp優(yōu)先級,《IEEE 1588-2008V2》并未規(guī)定dscp签夭,但AES67與RAVENNA標(biāo)準(zhǔn)對此有要求*/
  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);  //根據(jù)state machine更新狀態(tài),更新定時器
  }

  handle_state_decision_event(c);  //執(zhí)行bmc計算
}

enum fsm_event port_event(struct port *p)
{
    return p->event(p);  //如果是BC(Boundary Clock)或OC(Ordinary Clock)第租,執(zhí)行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小節(jié)
      delay_req_prune(p);         //移除過期的delay req message
      return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES;  //事件導(dǎo)致state machine更新狀態(tài)慎宾,見下面圖3

    case FD_DELAY_TIMER:
      port_set_delay_tmo(p);      //更新發(fā)送Delay_Req message或Pdelay_Req message的定時器丐吓,參考《IEEE 1588-2008V2》7.7.2.4小節(jié)和7.7.2.5小節(jié)
      delay_req_prune(p);         //移除過期的delay req message
      port_delay_request(p);      //如果是e2e機制,發(fā)送Delay_Req message趟据;如果是p2p機制券犁,發(fā)送Pdelay_Req message
      return EV_NONE;

    case FD_QUALIFICATION_TIMER:
      return EV_QUALIFICATION_TIMEOUT_EXPIRES;  //在PRE_MASTER等待了足夠的時間,狀態(tài)變?yōu)镸ASTER汹碱,見下面圖3

    case FD_MANNO_TIMER:
      port_set_manno_tmo(p);      //更新發(fā)送Announce message的定時器粘衬,參考《IEEE 1588-2008V2》7.7.2.2小節(jié)
      port_tx_announce(p);        //發(fā)送Announce message
      return EV_NONE;

    case FD_SYNC_TX_TIMER:
      port_set_sync_tx_tmo(p);    //更新發(fā)送Sync message的定時器,參考《IEEE 1588-2008V2》7.7.2.3小節(jié)
      port_tx_sync(p);            //發(fā)送Sync message
      return EV_NONE;

    case FD_RTNL:
      rtnl_link_status();         //監(jiān)控網(wǎng)卡狀態(tài)變化
      if (網(wǎng)卡狀態(tài)變更) 
        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小節(jié)
      break;

    case DELAY_REQ:
      process_delay_req(p, msg);      //處理Delay_Req message褂删,處理流程見下面圖5飞醉,參考《IEEE 1588-2008V2》9.5.6小節(jié)
      break;

    case PDELAY_REQ:
      process_pdelay_req(p, msg);     //處理Pdelay_Req message,發(fā)送Pdelay_Resp message和Pdelay_Resp_Follow_Up message屯阀,參考《IEEE 1588-2008V2》9.5.14和9.5.15小節(jié)
      break;

    case PDELAY_RESP:
      process_pdelay_resp(p, msg);    //處理Pdelay_Resp message缅帘,如果是one-step模式,計算鏈路傳播耗時难衰,參考《IEEE 1588-2008V2》11.4小節(jié)
      break;

    case FOLLOW_UP:
      process_follow_up(p, msg);      //處理Follow_Up message钦无,處理流程見下面圖6,參考《IEEE 1588-2008V2》9.5.5小節(jié)
      break;

    case DELAY_RESP:
      process_delay_resp(p, msg);     //處理Delay_Resp message召衔,處理流程見下面圖7铃诬,參考《IEEE 1588-2008V2》9.5.7小節(jié)
      break;

    case PDELAY_RESP_FOLLOW_UP:
      process_pdelay_resp_fup(p, msg); //處理Pdelay_Resp_Follow_Up message,計算鏈路傳播耗時苍凛,參考《IEEE 1588-2008V2》11.4小節(jié)
      break;

    case ANNOUNCE:
      process_announce(p, msg);        //處理Announce message趣席,處理流程見下面圖8,參考《IEEE 1588-2008V2》9.5.3小節(jié)
      break;

    case SIGNALING:
      process_signaling(p, msg);        //處理Signaling message醇蝴,參考《IEEE 1588-2008V2》16.1小節(jié)
      break;

    case MANAGEMENT:
      clock_manage(p->clock, p, msg);   //處理Management message宣肚,參考《IEEE 1588-2008V2》15.3小節(jié)
      break;
  }
}


圖3 ptp狀態(tài)機
圖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小節(jié)
void handle_state_decision_event(struct clock *c)
{
  LIST_FOREACH(piter, &c->ports, list) {
    fc = port_compute_best(piter);                    //port根據(jù)收到的Announce message選出最優(yōu)的foreign clock
    if (c->dscmp(&fc->dataset, &best->dataset) > 0)   //比較各個port的最優(yōu)foreign clock,選出全局最優(yōu)foreign clock悠栓,dscmp對比流程見下面圖9和圖10霉涨,參考《IEEE 1588-2008V2》9.3.4小節(jié)
      best = fc;
  }

  c->best = best;

  LIST_FOREACH(piter, &c->ports, list)
    bmc_state_decision(c, piter, c->dscmp);           //port根據(jù)新選出來的best clock更新各自的狀態(tài),更新邏輯見下面圖11惭适,參考《IEEE 1588-2008V2》9.3.3小節(jié)
}
圖9 Data set比較算法
圖10 Data set比較算法
圖11 bmc state decision算法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末笙瑟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子癞志,更是在濱河造成了極大的恐慌往枷,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凄杯,死亡現(xiàn)場離奇詭異错洁,居然都是意外死亡,警方通過查閱死者的電腦和手機戒突,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門屯碴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膊存,你說我怎么就攤上這事导而〕腊龋” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵嗡载,是天一觀的道長窑多。 經(jīng)常有香客問我,道長洼滚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任技潘,我火速辦了婚禮遥巴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘享幽。我一直安慰自己铲掐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布值桩。 她就那樣靜靜地躺著摆霉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奔坟。 梳的紋絲不亂的頭發(fā)上携栋,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音咳秉,去河邊找鬼婉支。 笑死,一個胖子當(dāng)著我的面吹牛澜建,可吹牛的內(nèi)容都是我干的向挖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼炕舵,長吁一口氣:“原來是場噩夢啊……” “哼何之!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咽筋,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤溶推,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晤硕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悼潭,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年舞箍,在試婚紗的時候發(fā)現(xiàn)自己被綠了舰褪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡疏橄,死狀恐怖占拍,靈堂內(nèi)的尸體忽然破棺而出略就,到底是詐尸還是另有隱情,我是刑警寧澤晃酒,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布表牢,位于F島的核電站,受9級特大地震影響贝次,放射性物質(zhì)發(fā)生泄漏崔兴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一蛔翅、第九天 我趴在偏房一處隱蔽的房頂上張望敲茄。 院中可真熱鬧,春花似錦山析、人聲如沸堰燎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秆剪。三九已至,卻和暖如春爵政,著一層夾襖步出監(jiān)牢的瞬間仅讽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工茂卦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留何什,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓等龙,卻偏偏與公主長得像处渣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛛砰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 計算機中的 system clock:system clock is maintained by the kern...
    SnC_閱讀 2,364評論 0 0
  • IEEE 1588協(xié)議簡單理解 ? IEEE 1588 是一個精密時間協(xié)議 (PTP)罐栈,用于同步計算機...
    fafactx閱讀 1,696評論 0 0
  • 1、數(shù)字音頻傳輸?shù)膬?yōu)點 傳統(tǒng)的模擬音頻傳輸存在信號損耗泥畅、電磁干擾和接地干擾等問題荠诬;而數(shù)字音頻傳輸抗干擾能力強,整個...
    myroncml閱讀 7,581評論 0 5
  • 關(guān)于時間這件小事 頻率 帶寬與頻率與頻率相關(guān)的另一個參數(shù)是數(shù)據(jù)傳輸率位仁,也稱為"帶寬"柑贞,用于衡量數(shù)據(jù)通信速度的快慢。...
    胡聿澤閱讀 1,091評論 0 0
  • 此recommendation的全名為 PTP telecom profile for phase/time sy...
    SnC_閱讀 4,319評論 0 0