0 前言
ptp4l是linuxptp-4.2的一部分。
1 main()
ptp4l的main()主要做三件事:
- 讀取配置。
- 調(diào)用功能config_create()創(chuàng)建
config實(shí)例,并從全局變量config_tab[]數(shù)組讀取默認(rèn)配置值。 - 調(diào)用config_create_interface(),從命令行選項(xiàng)解析網(wǎng)絡(luò)接口。
- 調(diào)用clock_read(),從配置文件讀取用戶配置值。
- 調(diào)用功能config_create()創(chuàng)建
- 調(diào)用clock_create()創(chuàng)建
clock實(shí)例,以及其下的port、transport、tsproc實(shí)例等。初始化每個(gè)port的定時(shí)器fd和socket fd。 - 在循環(huán)中調(diào)用clock_poll(),監(jiān)聽所有
fd的事件,如定時(shí)器超時(shí)、ptp消息到達(dá)等,派發(fā)處理。

2 config
config保存用戶配置項(xiàng)。配置項(xiàng)可以來自如下三個(gè)源:
- ptp4l的默認(rèn)配置項(xiàng)、
- ptp4l配置文件、
- 啟動(dòng)ptp4l的命令行選項(xiàng)。

2.1 config.interfaces
ptp4l可以同時(shí)指定多個(gè)網(wǎng)卡授時(shí),config.interfaces保存網(wǎng)卡列表。這是一個(gè)STAILQ,其定義來自于<sys/queue.h>。interfaces可以通過命令行或配置文件增加。
config_create_interface()創(chuàng)建interface實(shí)例。

interface的成員如下。
- 成員
list用于將interface連接成一個(gè)STAILQ。 - 成員
name是網(wǎng)卡的名字,ts_label一般與name相同。 - 成員
ts_info是網(wǎng)卡的時(shí)間戳支持特性,如timestamping、phc_index等。 - 成員
if_info是網(wǎng)卡的支持速率信息,如speed等。

2.2 config.htab
htab是一個(gè)hash表。所有的配置參數(shù)都以config_item格式保存在這個(gè)表中。
在config_create()中,創(chuàng)建htab,并從全局?jǐn)?shù)組config_tab[]中讀入?yún)?shù)。
struct config_item config_tab[] = {
PORT_ITEM_INT("allowedLostResponses", 3, 1, 255),
PORT_ITEM_INT("announceReceiptTimeout", 3, 2, UINT8_MAX),
PORT_ITEM_ENU("asCapable", AS_CAPABLE_AUTO, as_capable_enu),
...
}

在config_read()中,解析配置文件時(shí),從中讀出的參數(shù)值將覆蓋htab中的值。
config_read()的第一個(gè)參數(shù)是配置文件名,這是在命令行選項(xiàng)中指定的。

2.3 hash與node
hash實(shí)現(xiàn)了一個(gè)hash表。
- 成員
table是一個(gè)長度為200的數(shù)組,數(shù)組元素是node鏈表。
node是hash表中的節(jié)點(diǎn)。
- 成員
data和key分別是數(shù)據(jù)和它的關(guān)鍵字。

2.4 config.config_item
config_item是全局變量config_tab元素類型。
- 成員
label為參數(shù)名 -
config_type為參數(shù)類型,如int/double/enum/string等等。- 當(dāng)
config_type為int/double類型時(shí),成員val、min和max保存默認(rèn)值,最小、最大值; - 當(dāng)
config_type為enum類型時(shí),tab保存值; - 當(dāng)
config_type為string類型時(shí),成員val保存值。
- 當(dāng)
-
flags是參數(shù)標(biāo)志。比如是全局有效,還是只針對指定端口。

2.5 config.opts
opts是struct option數(shù)組。他用于調(diào)用getopt_long()函數(shù),從命令行選項(xiàng)獲取參數(shù)。
3 clock
clock定義時(shí)鐘節(jié)點(diǎn)。
- 成員
type按照角色定義clock類型,如普通節(jié)點(diǎn)、邊界節(jié)點(diǎn)、PTP節(jié)點(diǎn)等。 - 成員
timestamping按照打時(shí)間戳方式定義類型,如軟時(shí)鐘、硬時(shí)鐘等。 - 成員
ports是clock下屬的ports實(shí)例的列表。成員nports是ports實(shí)例數(shù)。 - 成員
pollfd數(shù)組,保存所有fd,用于監(jiān)聽。其中有所有port的fd,加上另外兩個(gè)UDS port的fd。 - 如果
pollfd數(shù)組準(zhǔn)備好,則成員pollfd_valid為true,否則為false。當(dāng)port的fd有變化時(shí),這個(gè)標(biāo)志可以告知監(jiān)聽函數(shù),應(yīng)該重建pollfd數(shù)組了。

4 port
port定義網(wǎng)絡(luò)接口,與config.interfaces是對應(yīng)的。
- 成員
list將port實(shí)例鏈接在一個(gè)列表中。 - 成員
name是網(wǎng)口名,比如eth0。 -
clock是port關(guān)聯(lián)的clock實(shí)例。 - 成員
trp是port的transport實(shí)例,負(fù)責(zé)收發(fā)網(wǎng)絡(luò)包。 - 成員
timestamping為打時(shí)間戳的方式,如TS_SOFTWARE、TS_HARDWARE等。 - 成員
fda的類型是fdarray。fdarray包含一個(gè)fd數(shù)組,數(shù)組長度是一個(gè)port需要?jiǎng)?chuàng)建的fd數(shù)。-
FD_PORT值是fd數(shù)組中的索引。其中FD_EVENT和FD_GENERAL對應(yīng)收發(fā)網(wǎng)絡(luò)包的socket; -
FD_DELAY_TIMER~FD_UNICAST_SRV_TIMER對應(yīng)定時(shí)器的fd, -
FD_RTNL對應(yīng)獲取端口信息的socket。
-
- 成員
phc_index是phc設(shè)備索引。 - 成員
state為port的當(dāng)前狀態(tài)。 - 成員
peer_pelday_req/peer_delay_resp/peer_delay_fup保存一個(gè)ptp消息序列。后面還會(huì)詳細(xì)說明。

4.1 port_state
port狀態(tài)state的變換是一個(gè)狀態(tài)機(jī),由fsm_event事件驅(qū)動(dòng)。
port_state定義port的狀態(tài)。

4.2 state_fsm
ptp master和ptp slave的狀態(tài)轉(zhuǎn)換的差異由port_fsm區(qū)分。比如,ptp master 的處理函數(shù)是designated_master_fsm、ptp slave的處理函數(shù)是designed_slave_fsm等等。

4.3 event dipatch
按照clock的角色看,不同角色的時(shí)間派發(fā)方式有差異。如邊界時(shí)鐘的處理函數(shù)是bc_dispatch/bc_event等。普通時(shí)鐘的處理函數(shù)與邊界時(shí)鐘相同。

5 transport
transport負(fù)責(zé)收發(fā)PTP消息。
基于PTP協(xié)議基于哪一層,有不同類型的transport。如:
-
IEEE_802_3基于mac層,如下raw是對應(yīng)的實(shí)現(xiàn)。 -
UDP_IPV4基于UDP協(xié)議,如下udp是對應(yīng)的實(shí)現(xiàn)。 -
UDP_IPV6基于UDP IPV6協(xié)議,如下udp6是對應(yīng)的實(shí)現(xiàn)。

6 tsproc
tsproc處理PTP消息。
- 它從PTP消息獲取時(shí)間戳,計(jì)算
ptp slave與ptp master的時(shí)間差,設(shè)置ptp slave的時(shí)間。這個(gè)時(shí)間差只是保存在ptp4l進(jìn)程,設(shè)置系統(tǒng)時(shí)間需要其他程序去做,如phc2sys。 - 成員t1、t2、t3、t4是當(dāng)前這個(gè)序列的PTP消息中的4個(gè)時(shí)間戳。
- 成員mode是計(jì)算時(shí)間差的方式。
-
TSPROC_RAW只考慮當(dāng)前序列的PTP消息。 -
TSPROC_FILTER則會(huì)參考最近幾個(gè)序列的PTP消息。成員filtered_delay 保存前幾個(gè)序列消息的數(shù)據(jù)。
-
-
TSPROC_FILTER模式下,delay_filter計(jì)算時(shí)間差。支持兩種類型的filter:mave_filter和mmedian_filter。

7 clock_create()
clock_create()創(chuàng)建時(shí)鐘節(jié)點(diǎn)。
- 將這個(gè)節(jié)點(diǎn)指向全局變量the_clock。這是ptp4l實(shí)例默認(rèn)的時(shí)鐘實(shí)例
struct clock the_clock;
- 讀取config,配置clock的參數(shù)。
- 調(diào)用config_harmonize_onestep()檢查用戶配置參數(shù)是否一致。比如只有軟時(shí)鐘不能使用one_step方式等。
- 調(diào)用clock_required_modes(),根據(jù)用戶設(shè)置,得到clock需要支持的屬性,如SOF_TIMESTAMPING_SOFTWARE、 SOF_TIMESTAMPING_RAW_HARDWARE等。
- 遍歷config中的所有interface,
- 調(diào)用interface_get_ifinfo()得到interface的速度屬性
- 調(diào)用interface_get_tsinfo()得到interface的時(shí)鐘屬性。然后調(diào)用interface_tsmodes_supported(),檢查interface是否滿足
clock_required_modes()的要求,如果不滿足,返回失敗。
- 調(diào)用interface_phc_index()得到interface的phc設(shè)備索引phc_index。這里是
0,所以phc_device是/dev/ptp0。 - 調(diào)用generate_clock_identity(),產(chǎn)生clock的indentity,這個(gè)用于在PTP通信中唯一標(biāo)識clock。

- 調(diào)用phc_open()打開phc設(shè)備
/dev/ptp0. - 調(diào)用phc_max_adj()/clockadj_get_freq(),得到時(shí)鐘最大調(diào)整范圍。
- 根據(jù)用戶配置,設(shè)置clock->dscmp = dscmp。這個(gè)函數(shù)比較兩個(gè)clock,根據(jù)priority/quality.clockCalss/qulity.clockAccuracy決定哪個(gè)clock更好。這里指定的dscmp是一個(gè)全局函數(shù)。
- 調(diào)用tsproc_create(),創(chuàng)建ts_proc實(shí)例,其中根據(jù)配置創(chuàng)建相應(yīng)的filter,保存在tsproc->filter。

- 遍歷clock的所有interface,調(diào)用clock_add_port(),創(chuàng)建port實(shí)例。
- 調(diào)用clock_resize_pollfd(),根據(jù)計(jì)算的fd數(shù),調(diào)整clock.fdarray[]數(shù)組大小。
- 調(diào)用port_open()創(chuàng)建port實(shí)例,并將它加入隊(duì)列clock->ports中。
- 調(diào)用clock_fda_changed()設(shè)置標(biāo)志clock->pollfd_valid。后面clock_check_pollfd()會(huì)根據(jù)這個(gè)標(biāo)志,判斷是否需要重新配置fd監(jiān)聽列表clock->pollfd。
- 調(diào)用port_dispatch(),處理EV_INITIALIZE事件,初始化port。

8 port_open()
port_open()創(chuàng)建端口。
- malloc()創(chuàng)建port實(shí)例。
- 根據(jù)clock角色指定port的事件處理函數(shù)。這里是ordinary_clock,所以指定bc_dispatch/bc_event。
bc指boundary clock。oridinay_clock的處理與它的相同。 - 調(diào)用transport_create()。
- 根據(jù)用戶指定的transport_type,創(chuàng)建transport實(shí)例。這里是IEEE_802_3協(xié)議,所以調(diào)用raw_transport_create()創(chuàng)建raw實(shí)例。raw的處理函數(shù)是raw_open()/raw_send()/raw_recv()。
- 根據(jù)clock的主從關(guān)系,如
BMCA/master_only/slave_only設(shè)置項(xiàng),指定port的處理函數(shù)。- 如果指定
BMCA=NOOP,master_only=true,則是designated_master_fsm, - 如果指定
BMCA=NOOP,slave_only=true,則是designated_slave_fsm。
- 如果指定
- 調(diào)用port_clear_fda()清除port->fdarray。
- 調(diào)用timerfd_create()創(chuàng)建port->fault_fd。

9 bc_dispatch()
bc_dispatch() 處理事件驅(qū)動(dòng)port的狀態(tài)機(jī)。
- 調(diào)用port_state_update()。
- 初始化時(shí)處理事件
EV_INITIALIZE。如果是ptp master,則designated_master_fsm()會(huì)將狀態(tài)轉(zhuǎn)換成PS_MASTER;如果是ptp slave,則designated_slave_fsm()會(huì)將狀態(tài)轉(zhuǎn)換成PS_SLAVE。 - 調(diào)用port_initialize()初始化port。
- 如果有狀態(tài)變化發(fā)生,則調(diào)用port_show_transition()打印狀態(tài)轉(zhuǎn)換消息,如果沒有,直接返回
- 初始化時(shí)處理事件
- 如果沒有狀態(tài)變化,則根據(jù)delayMechanism選項(xiàng)設(shè)置(
DM_PSP/DS_E2E),調(diào)用相應(yīng)的處理函數(shù),這里為delayMechanism =DM_P2P,則調(diào)用port_p2p_transition()。它的主要工作是設(shè)置port各個(gè)計(jì)時(shí)器的超時(shí)時(shí)間。

10 port_initialize()
port_initialize()初始化port實(shí)例。
- 讀取config,初始化port的參數(shù)。
- 調(diào)用timerfd_create(),創(chuàng)建所有的計(jì)時(shí)器fd。
- 調(diào)用transport_open(),其中調(diào)用transport->open,這里是raw_open()。
- 調(diào)用rtnl_open()創(chuàng)建port的
RTNL socket,這個(gè)socket用于查詢port的連接狀態(tài)。然后用rtnl_link_query()來查詢。 - 調(diào)用clock_fda_changed()設(shè)置port->pollfd_valid標(biāo)志。后面clock_check_pollfd()會(huì)根據(jù)這個(gè)標(biāo)志,判斷是否重新配置clock的fd監(jiān)聽列表clock->pollfd。

11 raw_open()
raw_open()創(chuàng)建PTP通信的socket。
- 調(diào)用mac_to_addr(),將PTP目標(biāo)地址從字符串轉(zhuǎn)換成MAC地址。
- 調(diào)用sk_interface_macaddr(),得到本地MAC地址。
- 調(diào)用open_socket()創(chuàng)建兩個(gè)socket,這是用于PTP通信的socket。
- 調(diào)用sk_timstamping_init()初始化socket的時(shí)間戳選項(xiàng),如
SOF_TIMESTAMPING_BIND_PHC/SOF_TIMESTAMPING_SOFTWARE/SOF_TIMESTAMPING_RAW_HARDWARE等。 - 將兩個(gè)socket保存到port的fd數(shù)組中。

12 open_socket()
open_socket()創(chuàng)建PTP socket,并配置。
- 調(diào)用socket()創(chuàng)建socket實(shí)例,并調(diào)用set_socket_opt()設(shè)置選項(xiàng),如
SO_PRIORITY。 - 調(diào)用raw_configure()進(jìn)一步配置其他選項(xiàng),如加入組播組。
socket套接字網(wǎng)卡綁定和優(yōu)先級調(diào)整

13 clock_poll()
clock_poll()監(jiān)聽port的fd的事件,并處理。
- 調(diào)用clock_check_pollfd()。如果clock->pollfd_valid = false, 則遍歷clock所屬ports,用port的所有fd填充clock->pollfd。
- 調(diào)用poll監(jiān)聽clock->pollfd數(shù)組,信號到達(dá)時(shí)(定時(shí)器超時(shí)或收到PTP消息),進(jìn)行處理,否則返回。
- 遍歷ports,
- 遍歷port的所有fd,調(diào)用port_state()得到port狀態(tài),調(diào)用port_event()處理事件,這里實(shí)際上調(diào)用bc_event();
- 如果是EV_STATE_DECISION_EVENT,則設(shè)置c->sde = 1,這種情況下,后面調(diào)用handle_state_decision_event()進(jìn)行處理。
- 調(diào)用port_dispatch()處理事件,這里實(shí)際上會(huì)調(diào)用bc_dispatch()。

14 handle_state_decision_event()
handle_state_desision_event()在收到EV_STATE_DECISON_EVENT時(shí),決定使用哪個(gè)port。
不同的port接入各自的網(wǎng)絡(luò),每個(gè)網(wǎng)絡(luò)上可以比較得到一個(gè)最好的clock。也就是每個(gè)port有一個(gè)最好的clock。而clock的最好的clock,則是所有port的clock中最好的一個(gè)。
- 遍歷clock的所有port,調(diào)用port_compute_best(),計(jì)算它的外接clock節(jié)點(diǎn)中哪個(gè)最好。如果本地變量best =
NULL,則保存到best中,否則與best比較,如果比best更好,則替換best。同時(shí)將它的identity則保存到本地變量best_id中。 - 比較best_id與clock->best_id不同,則重置clock的相關(guān)參數(shù),如clock_freq、tsproc等。
- 比較best_id與clock自己的dds.clockIdentity,如果相同,則打印”select local clock xxx as best master”,這說明自己就是網(wǎng)絡(luò)上最好的時(shí)鐘;如果不同,則打印”selected best master clock xxx”,這意味最好的時(shí)鐘是別人。
- 遍歷ports,調(diào)用bmc_state_decision(),計(jì)算這個(gè)port的狀態(tài),如PS_GRAND_MASTER、PS_MASTER、PS_SLAVE等。調(diào)用clock_update_grand_master()/clock_update_slave()更新clock的parentDS狀態(tài)。
- 調(diào)用port_disptach()進(jìn)行其他處理。對于
EV_STATE_DECISION_EVENT事件,其實(shí)沒有什么其他處理了。

15 bc_event() + FD_RTNL
FD_RTNL消息是網(wǎng)絡(luò)斷開和連接造成的。這里調(diào)用rtnl_link_status()處理。
- 調(diào)用recvmsg()接收RTNL消息,并調(diào)用rtnl_attr_parse()和rtnl_linkinfo_parse()解析,得到port的連接狀態(tài),并調(diào)用port_link_status()。后者
- 調(diào)用interface_get_ifinfo()和interface_get_tsinfo()得到port信息。
- 調(diào)用port_change_phc(),更改phc設(shè)備
- 調(diào)用clock_set_sde(),告知handle_state_decision_event(),需要重新決定最好的clock。

16 bc_event() FD_MANNO_TIMER (PTP MASTER端)
FD_MANNO_TIMER定時(shí)器超時(shí),bc_event()處理,發(fā)送announce_msg消息。這個(gè)消息是PTP MASTER對外公告自己的clock參數(shù),以便與其他節(jié)點(diǎn)協(xié)商最佳clock。
- 調(diào)用port_tx_announce()。其中,創(chuàng)建announce_msg消息,設(shè)置domainNumber/sourcePortIdentity/sequence_id屬性,調(diào)用port_prepare_and_send()發(fā)送。

17 bc_event() ANNOUNCE (PTP SLAVE端)
收到announce_msg消息,bc_event()處理。
- 調(diào)用process_announce(),它又調(diào)用update_current_master()。其中,
- 將發(fā)出這個(gè)消息的foreign clock不是port_>best,則調(diào)用add_foreigin_master(),將它加入port->foreigin_master。否則,
- 將消息加入fc->messages中。調(diào)用announce_compare()對fc->messages中的消息進(jìn)行比較,如果新消息的foreigin_clock導(dǎo)致外部最佳時(shí)鐘變化,則返回1。
- process_announce()返回1時(shí),bc_event()會(huì)返回
EV_STATE_DECISiON_DEVENT。如前所述,這會(huì)導(dǎo)致調(diào)用handle_state_decision_event(),重新選擇最佳外部時(shí)鐘。

18 bc_event() FD_SYNC_TX_TIMER (PTP MASTER端)
FD_SYNC_TX_TIMER定時(shí)器超時(shí),bc_event()處理,發(fā)送sync_msg和follow_up_msg消息。通過sync_msg消息,PTP MASTER發(fā)送自己的時(shí)間基準(zhǔn)數(shù)據(jù),follow_up_msg則可以讓這個(gè)數(shù)據(jù)更精準(zhǔn)。
- 調(diào)用port_tx_sync()。其中,
- 創(chuàng)建sysnc_msg消息,調(diào)用port_prepare_and_send()發(fā)送。
- 創(chuàng)建follow_up_msg消息,調(diào)用port_prepare_and_send()發(fā)送。

19 bc_event() SYNC (PTP SLAVE端)
收到SYNC消息,bc_event()處理。
- 調(diào)用process_sync()。其中,
- 調(diào)用port_syfufsm()處理,計(jì)算與PTP MASTER的時(shí)間差。

20 bc_event() FD_SYNC_TX_TIMER (PTP SLAVE端)
收到FOLLOW_UP消息,bc_event()處理。
- 調(diào)用process_follow_up()。其中,
- 調(diào)用port_syfufsm()處理,精確計(jì)算與PTP MASTER的時(shí)間差。port_syfufsm()的時(shí)間參數(shù)來自sync_msg和follow_up_msg。

21 port_syfufsm()
port_syfufsm()根據(jù)時(shí)間戳數(shù)據(jù)計(jì)算時(shí)間差,并將PTP SLAVE與PTP MASTER調(diào)整到一致(不是很精確的一致)。
- 它調(diào)用port_synchronze(),后者又調(diào)用clock_synchronize()。其中,
- 調(diào)用servo_sample(),從累積數(shù)據(jù)中得到時(shí)間差
- 調(diào)用clockadj_set_freq()和clockadj_step(),調(diào)整本地時(shí)間。

22 PTP消息序列
對于gPTP,每個(gè)PTP消息序列應(yīng)該有3個(gè)消息:PDelay_Req、PDelay_Resp、PDelay_Resp_Follow_Up。

步驟如下。
- PTP Slave 發(fā)送
PDelay_Req消息。源MAC地址是ptp slave的網(wǎng)卡地址。SourcePortID+sequenceId唯一標(biāo)識這個(gè)消息序列。

- PTP Master 發(fā)送
PDelay_Resp消息。源MAC地址是master的網(wǎng)卡地址。這里的SourcePortID+sequenceId與PDelay_Req消息的相同,所以是同一個(gè)消息序列。它攜帶時(shí)間戳T2。

- PTP Master 發(fā)送
PDelay_Resp_Follow_Up消息。源MAC地址是master的網(wǎng)卡地址。這里的SourcePortID+sequenceId與PDelay_Req消息的相同,所以是同一個(gè)消息序列。它攜帶時(shí)間戳T3。

在PTP slave端,port的成員peer_pelday_req/peer_delay_resp/peer_delay_fup保存這個(gè)ptp消息序列的3個(gè)消息。后面依次說明這幾個(gè)消息的處理。
23 bc_event() FD+DELAY_TIMER (PTP SLAVE端)
PTP SLAVE端的定時(shí)器超時(shí)觸發(fā),bc_event()處理。
- 調(diào)用port_delay_request(),發(fā)送
pdelay_req_msg消息,其中,- 創(chuàng)建
pdelay_req_msg消息,設(shè)置消息的domainaNumber/sourcePortIdentity/sequenceId`值,然后調(diào)用port_prepare_and_send()發(fā)送。 - 這里還設(shè)置消息的
msg.hwts.type,告訴網(wǎng)口給消息打時(shí)間戳,也就是T1。 -
pdelay_req_msg消息同時(shí)保存在port.peer_pdelay_req。
- 創(chuàng)建

24 bc_event() DELAY_REQ (PTP MASTER端)
收到PTP Slave發(fā)送的pdelay_req_msg消息,bc_event()處理。
- 調(diào)用process_pdelay_req(),其中,
- 創(chuàng)建
pdelay_resp_msg消息,設(shè)置domainNumber/requestingPortIdentity/sequenceId值,然后發(fā)送。這里還設(shè)置了網(wǎng)卡接收pdelay_req_msg消息打的時(shí)間戳,也就是T2。 - 創(chuàng)建
pdelay_resp_fup_msg消息,設(shè)置domainNumber/requestingPortIdentity/sequenceId值,然后發(fā)送。這里還設(shè)置了網(wǎng)口發(fā)送pdelay_resp_msg消息打的時(shí)間戳,也就是T3。
- 創(chuàng)建

25 bc_event() PDELAY_RESP (PTP SLAVE端)
收到PTP MASTER發(fā)送的pdelay_resp_msg消息,bc_event()處理。
- 將消息保存在
port.peer_delay_resp。 - 調(diào)用process_pdelay_resp()。對于
two_step模式,因?yàn)?code>4個(gè)時(shí)間戳還不全,現(xiàn)在還不會(huì)做計(jì)算。

26.bc_event() PDELAY_RESP_FOLLOW_UP (PTP SLAVE端)
收到pdelay_resp_fup_msg消息,bc_event()處理。
- 將消息保存到
port.peer_delay_fup - 調(diào)用process_pdelay_resp()?,F(xiàn)在有了所有
4個(gè)時(shí)間戳,可以計(jì)算與PTP Master的時(shí)間差了。

27 port_peer_delay()
port_peer_delay()根據(jù)4個(gè)時(shí)間戳計(jì)算時(shí)間差。
- 調(diào)用pid_eq()檢查
portIdentity是否匹配 - 計(jì)算
t4 - t1 - 計(jì)算
t3 - t2 - 調(diào)用tsproc_update_delay()計(jì)算時(shí)間差。調(diào)用clock_peer_delay()更新本地時(shí)間戳。
