liunxptp 代码学习

PTP协议栈详解

  • 场景一
    • 延迟机制的基本原理
    • 协议栈的过程
  • 一、step 1: master->slave(sync报文的发送和sync的follow_up报文的发送)
  • 二、step 2: slave->master(接受sync报文和follow up和发送delay_req)
  • 三、step4:master->slave(接受delay_req和发送resp_报文)
  • 四、step 4: slave接受delay_resp报文

场景一

当我们配置时钟A为OC且一个端口为master,一个时钟B为BC,一个端口为slave,且延迟机制为E2E。

延迟机制的基本原理

延迟机制的算法方式

协议栈的过程

一、step 1: master->slave(sync报文的发送和sync的follow_up报文的发送)

int clock_poll(struct clock *c)
{int cnt, i;enum fsm_event event;struct pollfd *cur;struct port *p;clock_check_pollfd(c);cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);if (cnt < 0) {if (EINTR == errno) {return 0;} else {pr_emerg("poll failed");return -1;}} else if (!cnt) {return 0;}cur = c->pollfd;LIST_FOREACH(p, &c->ports, list) {/* Let the ports handle their events. */for (i = 0; i < N_POLLFD; i++) {if (cur[i].revents & (POLLIN|POLLPRI|POLLERR)) {if (cur[i].revents & POLLERR) {pr_err("port %d: unexpected socket error",port_number(p));event = EV_FAULT_DETECTED;} else {/*引发事件,这是一个回调,当为0C/BC是回调bc_event,E2ETC时回e2e_event.P2PTC时回调p2p_event*/event = port_event(p, i);}/* 推荐状态事件是由STATE—DECISION—EVENT引发的执行最佳主时钟算法的结果*/if (EV_STATE_DECISION_EVENT == event) {c->sde = 1;}/* see 9.2.6 */if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event) {c->sde = 1;}port_dispatch(p, event, 0);/* Clear any fault after a little while. */if (PS_FAULTY == port_state(p)) {clock_fault_timeout(p, 1);break;}}}

bc_event的代码

// bc_event
static enum fsm_event bc_event(struct port *p, int fd_index)
{enum fsm_event event = EV_NONE;struct ptp_message *msg;int cnt, fd = p->fda.fd[fd_index], err;/*时钟自己发送的请求*/switch (fd_index) {case FD_ANNOUNCE_TIMER:case FD_SYNC_RX_TIMER:pr_debug("port %hu: %s timeout", portnum(p),fd_index == FD_SYNC_RX_TIMER ? "rx sync" : "announce");if (p->best) {fc_clear(p->best);}/** Clear out the event returned by poll(). It is only cleared* in port_*_transition(). But, when BMCA == 'noop', there is no* state transition. So, it won't be cleared anywhere else.*/if (p->bmca == BMCA_NOOP) {port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]);}if (p->inhibit_announce) {port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]);} else {port_set_announce_tmo(p);}delay_req_prune(p);if (clock_slave_only(p->clock) && p->delayMechanism != DM_P2P &&port_renew_transport(p)) {return EV_FAULT_DETECTED;}if (p->inhibit_announce) {return EV_NONE;}return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES;case FD_DELAY_TIMER:pr_debug("port %hu: delay timeout", portnum(p));port_set_delay_tmo(p);delay_req_prune(p);return port_delay_request(p) ? EV_FAULT_DETECTED : EV_NONE;case FD_QUALIFICATION_TIMER:pr_debug("port %hu: qualification timeout", portnum(p));return EV_QUALIFICATION_TIMEOUT_EXPIRES;case FD_MANNO_TIMER:pr_debug("port %hu: master tx announce timeout", portnum(p));port_set_manno_tmo(p);return port_tx_announce(p, NULL) ? EV_FAULT_DETECTED : EV_NONE;case FD_SYNC_TX_TIMER:pr_debug("port %hu: master sync timeout", portnum(p));port_set_sync_tx_tmo(p);/*处于master端口应周期性的发送sync报文,sync报文应多播方式发送*/return port_tx_sync(p, NULL) ? EV_FAULT_DETECTED : EV_NONE;case FD_UNICAST_SRV_TIMER:pr_debug("port %hu: unicast service timeout", portnum(p));return unicast_service_timer(p) ? EV_FAULT_DETECTED : EV_NONE;case FD_UNICAST_REQ_TIMER:pr_debug("port %hu: unicast request timeout", portnum(p));return unicast_client_timer(p) ? EV_FAULT_DETECTED : EV_NONE;case FD_RTNL:pr_debug("port %hu: received link status notification", portnum(p));rtnl_link_status(fd, p->name, port_link_status, p);if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))return EV_FAULT_CLEARED;else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) ||(p->link_status & TS_LABEL_CHANGED))return EV_FAULT_DETECTED;elsereturn EV_NONE;}msg = msg_allocate();if (!msg)return EV_FAULT_DETECTED;msg->hwts.type = p->timestamping;/*时钟接收到的报文*/cnt = transport_recv(p->trp, fd, msg);if (cnt < 0) {pr_err("port %hu: recv message failed", portnum(p));msg_put(msg);return EV_FAULT_DETECTED;}err = msg_post_recv(msg, cnt);if (err) {switch (err) {case -EBADMSG:pr_err("port %hu: bad message", portnum(p));break;case -EPROTO:pr_debug("port %hu: ignoring message", portnum(p));break;}msg_put(msg);return EV_NONE;}port_stats_inc_rx(p, msg);if (port_ignore(p, msg)) {msg_put(msg);return EV_NONE;}if (msg_sots_missing(msg) &&!(p->timestamping == TS_P2P1STEP && msg_type(msg) == PDELAY_REQ)) {pr_err("port %hu: received %s without timestamp",portnum(p), msg_type_string(msg_type(msg)));msg_put(msg);return EV_NONE;}if (msg_sots_valid(msg)) {ts_add(&msg->hwts.ts, -p->rx_timestamp_offset);clock_check_ts(p->clock, tmv_to_nanoseconds(msg->hwts.ts));}/*对收到的报文进行处理*/switch (msg_type(msg)) {case SYNC:process_sync(p, msg);break;case DELAY_REQ:if (process_delay_req(p, msg))event = EV_FAULT_DETECTED;break;case PDELAY_REQ:if (process_pdelay_req(p, msg))event = EV_FAULT_DETECTED;break;case PDELAY_RESP:if (process_pdelay_resp(p, msg))event = EV_FAULT_DETECTED;break;case FOLLOW_UP:process_follow_up(p, msg);break;case DELAY_RESP:process_delay_resp(p, msg);break;case PDELAY_RESP_FOLLOW_UP:process_pdelay_resp_fup(p, msg);break;case ANNOUNCE:if (process_announce(p, msg))event = EV_STATE_DECISION_EVENT;break;case SIGNALING:if (process_signaling(p, msg)) {event = EV_FAULT_DETECTED;}break;case MANAGEMENT:if (clock_manage(p->clock, p, msg))event = EV_STATE_DECISION_EVENT;break;}msg_put(msg);return event;
}

bc_event中有两个switch(msg_type),第一个主动发出的报文,第二个对接收到的报文进行处理。

int port_tx_announce(struct port *p, struct address *dst)
{struct timePropertiesDS tp = clock_time_properties(p->clock);struct parent_ds *dad = clock_parent_ds(p->clock);struct ptp_message *msg;int err;if (p->inhibit_multicast_service && !dst) {return 0;}if (!port_capable(p)) {return 0;}msg = msg_allocate();if (!msg) {return -1;}msg->hwts.type = p->timestamping;msg->header.tsmt               = ANNOUNCE | p->transportSpecific;msg->header.ver                = PTP_VERSION;msg->header.messageLength      = sizeof(struct announce_msg);msg->header.domainNumber       = clock_domain_number(p->clock);msg->header.sourcePortIdentity = p->portIdentity;msg->header.sequenceId         = p->seqnum.announce++;msg->header.control            = CTL_OTHER;msg->header.logMessageInterval = p->logAnnounceInterval;msg->header.flagField[1] = tp.flags;if (dst) {msg->address = *dst;msg->header.flagField[0] |= UNICAST;}msg->announce.currentUtcOffset        = tp.currentUtcOffset;msg->announce.grandmasterPriority1    = dad->pds.grandmasterPriority1;msg->announce.grandmasterClockQuality = dad->pds.grandmasterClockQuality;msg->announce.grandmasterPriority2    = dad->pds.grandmasterPriority2;msg->announce.grandmasterIdentity     = dad->pds.grandmasterIdentity;msg->announce.stepsRemoved            = clock_steps_removed(p->clock);msg->announce.timeSource              = tp.timeSource;if (p->path_trace_enabled && path_trace_append(p, msg, dad)) {pr_err("port %hu: append path trace failed", portnum(p));}err = port_prepare_and_send(p, msg, TRANS_GENERAL);if (err) {pr_err("port %hu: send announce failed", portnum(p));}msg_put(msg);return err;
}
int port_tx_sync(struct port *p, struct address *dst)
{struct ptp_message *msg, *fup;int err, event;/*如果是master报文,会配置时间戳类型为TS_HARDWARE,因此发送的sync报文为事件报文,需要打上tx时间戳*/switch (p->timestamping) {case TS_SOFTWARE:case TS_LEGACY_HW:case TS_HARDWARE:event = TRANS_EVENT;break;case TS_ONESTEP:event = TRANS_ONESTEP;break;case TS_P2P1STEP:event = TRANS_P2P1STEP;break;default:return -1;}if (p->inhibit_multicast_service && !dst) {return 0;}if (!port_capable(p)) {return 0;}if (port_sync_incapable(p)) {return 0;}msg = msg_allocate();if (!msg) {return -1;}fup = msg_allocate();if (!fup) {msg_put(msg);return -1;}msg->hwts.type = p->timestamping;msg->header.tsmt               = SYNC | p->transportSpecific;msg->header.ver                = PTP_VERSION;msg->header.messageLength      = sizeof(struct sync_msg);msg->header.domainNumber       = clock_domain_number(p->clock);msg->header.sourcePortIdentity = p->portIdentity;msg->header.sequenceId         = p->seqnum.sync++;msg->header.control            = CTL_SYNC;msg->header.logMessageInterval = p->logSyncInterval;if (p->timestamping != TS_ONESTEP && p->timestamping != TS_P2P1STEP) {msg->header.flagField[0] |= TWO_STEP;}/*如果master接收到单播请求,则发出sync报文的目的地址为单播请求方*/if (dst) {msg->address = *dst;msg->header.flagField[0] |= UNICAST;msg->header.logMessageInterval = 0x7f;}/*准备和发送报文*/err = port_prepare_and_send(p, msg, event);if (err) {pr_err("port %hu: send sync failed", portnum(p));goto out;}if (p->timestamping == TS_ONESTEP || p->timestamping == TS_P2P1STEP) {goto out;} else if (msg_sots_missing(msg)) {pr_err("missing timestamp on transmitted sync");err = -1;goto out;}/** Send the follow up message right away.*/fup->hwts.type = p->timestamping;fup->header.tsmt               = FOLLOW_UP | p->transportSpecific;fup->header.ver                = PTP_VERSION;fup->header.messageLength      = sizeof(struct follow_up_msg);fup->header.domainNumber       = clock_domain_number(p->clock);fup->header.sourcePortIdentity = p->portIdentity;fup->header.sequenceId         = p->seqnum.sync - 1;fup->header.control            = CTL_FOLLOW_UP;fup->header.logMessageInterval = p->logSyncInterval;fup->follow_up.preciseOriginTimestamp = tmv_to_Timestamp(msg->hwts.ts);if (dst) {fup->address = *dst;fup->header.flagField[0] |= UNICAST;}if (p->follow_up_info && follow_up_info_append(fup)) {pr_err("port %hu: append fup info failed", portnum(p));err = -1;goto out;}err = port_prepare_and_send(p, fup, TRANS_GENERAL);if (err) {pr_err("port %hu: send follow up failed", portnum(p));}
out:msg_put(msg);msg_put(fup);return err;
}
int port_prepare_and_send(struct port *p, struct ptp_message *msg,enum transport_event event)
{int cnt;if (msg_pre_send(msg)) {return -1;}if (msg_unicast(msg)) {/*这里会直接发送报文(这里的报文携带时间戳),p->trp是负载报文,可以按照协议类型组成的,由socket组包和发包*/cnt = transport_sendto(p->trp, &p->fda, event, msg);} else {cnt = transport_send(p->trp, &p->fda, event, msg);}if (cnt <= 0) {return -1;}port_stats_inc_tx(p, msg);if (msg_sots_valid(msg)) {/*这里需要考虑一下, p->tx_timestamp_offset可能是0*/ts_add(&msg->hwts.ts, p->tx_timestamp_offset);}return 0;
}
static int raw_send(struct transport *t, struct fdarray *fda,enum transport_event event, int peer, void *buf, int len,struct address *addr, struct hw_timestamp *hwts)
{struct raw *raw = container_of(t, struct raw, t);ssize_t cnt;unsigned char pkt[1600], *ptr = buf;struct eth_hdr *hdr;int fd = -1;switch (event) {case TRANS_GENERAL:fd = fda->fd[FD_GENERAL];break;case TRANS_EVENT:case TRANS_ONESTEP:case TRANS_P2P1STEP:case TRANS_DEFER_EVENT:fd = fda->fd[FD_EVENT];break;}ptr -= sizeof(*hdr);len += sizeof(*hdr);if (!addr)addr = peer ? &raw->p2p_addr : &raw->ptp_addr;hdr = (struct eth_hdr *) ptr;addr_to_mac(&hdr->dst, addr);addr_to_mac(&hdr->src, &raw->src_addr);hdr->type = htons(ETH_P_1588);/*内核协议栈为这类报文打上时间戳*/cnt = send(fd, ptr, len, 0);if (cnt < 1) {return -errno;}/** Get the time stamp right away.*/return event == TRANS_EVENT ? sk_receive(fd, pkt, len, NULL, hwts, MSG_ERRQUEUE) : cnt;
}

这里raw_send();是L2的报文。

二、step 2: slave->master(接受sync报文和follow up和发送delay_req)

static int raw_recv(struct transport *t, int fd, void *buf, int buflen,struct address *addr, struct hw_timestamp *hwts)
{int cnt, hlen;unsigned char *ptr = buf;struct eth_hdr *hdr;struct raw *raw = container_of(t, struct raw, t);if (raw->vlan) {hlen = sizeof(struct vlan_hdr);} else {hlen = sizeof(struct eth_hdr);}ptr    -= hlen;buflen += hlen;hdr = (struct eth_hdr *) ptr;cnt = sk_receive(fd, ptr, buflen, addr, hwts, MSG_DONTWAIT);if (cnt >= 0)cnt -= hlen;if (cnt < 0)return cnt;if (raw->vlan) {if (ETH_P_1588 == ntohs(hdr->type)) {pr_notice("raw: disabling VLAN mode");raw->vlan = 0;}} else {if (ETH_P_8021Q == ntohs(hdr->type)) {pr_notice("raw: switching to VLAN mode");raw->vlan = 1;}}return cnt;
}
int sk_receive(int fd, void *buf, int buflen,struct address *addr, struct hw_timestamp *hwts, int flags)
{char control[256];int cnt = 0, res = 0, level, type;struct cmsghdr *cm;struct iovec iov = { buf, buflen };struct msghdr msg;struct timespec *sw, *ts = NULL;memset(control, 0, sizeof(control));memset(&msg, 0, sizeof(msg));if (addr) {msg.msg_name = &addr->ss;msg.msg_namelen = sizeof(addr->ss);}msg.msg_iov = &iov;msg.msg_iovlen = 1;msg.msg_control = control;msg.msg_controllen = sizeof(control);if (flags == MSG_ERRQUEUE) {struct pollfd pfd = { fd, sk_events, 0 };res = poll(&pfd, 1, sk_tx_timeout);if (res < 1) {pr_err(res ? "poll for tx timestamp failed: %m" :"timed out while polling for tx timestamp");pr_err("increasing tx_timestamp_timeout may correct ""this issue, but it is likely caused by a driver bug");return -errno;} else if (!(pfd.revents & sk_revents)) {pr_err("poll for tx timestamp woke up on non ERR event");return -1;}}/*接受这个报文*/cnt = recvmsg(fd, &msg, flags);if (cnt < 0) {pr_err("recvmsg%sfailed: %m",flags == MSG_ERRQUEUE ? " tx timestamp " : " ");}for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {level = cm->cmsg_level;type  = cm->cmsg_type;/*https://blog.csdn.net/yeyuangen/article/details/21943925*/if (SOL_SOCKET == level && SO_TIMESTAMPING == type) {if (cm->cmsg_len < sizeof(*ts) * 3) {pr_warning("short SO_TIMESTAMPING message");return -EMSGSIZE;}ts = (struct timespec *) CMSG_DATA(cm);}if (SOL_SOCKET == level && SO_TIMESTAMPNS == type) {if (cm->cmsg_len < sizeof(*sw)) {pr_warning("short SO_TIMESTAMPNS message");return -EMSGSIZE;}sw = (struct timespec *) CMSG_DATA(cm);hwts->sw = timespec_to_tmv(*sw);}}if (addr)addr->len = msg.msg_namelen;if (!ts) {memset(&hwts->ts, 0, sizeof(hwts->ts));return cnt < 1 ? -errno : cnt;}switch (hwts->type) {case TS_SOFTWARE:hwts->ts = timespec_to_tmv(ts[0]);break;case TS_HARDWARE:case TS_ONESTEP:case TS_P2P1STEP:hwts->ts = timespec_to_tmv(ts[2]);break;case TS_LEGACY_HW:hwts->ts = timespec_to_tmv(ts[1]);break;}return cnt < 1 ? -errno : cnt;
}

接收到sync报文,并记录下接受时戳,t2 放进hwts_ts里。

int msg_post_recv(struct ptp_message *m, int cnt)
{int err, pdulen, suffix_len, type;if (cnt < sizeof(struct ptp_header))return -EBADMSG;err = hdr_post_recv(&m->header);if (err)return err;type = msg_type(m);switch (type) {case SYNC:pdulen = sizeof(struct sync_msg);break;case DELAY_REQ:pdulen = sizeof(struct delay_req_msg);break;case PDELAY_REQ:pdulen = sizeof(struct pdelay_req_msg);break;case PDELAY_RESP:pdulen = sizeof(struct pdelay_resp_msg);break;case FOLLOW_UP:pdulen = sizeof(struct follow_up_msg);break;case DELAY_RESP:pdulen = sizeof(struct delay_resp_msg);break;case PDELAY_RESP_FOLLOW_UP:pdulen = sizeof(struct pdelay_resp_fup_msg);break;case ANNOUNCE:pdulen = sizeof(struct announce_msg);break;case SIGNALING:pdulen = sizeof(struct signaling_msg);break;case MANAGEMENT:pdulen = sizeof(struct management_msg);break;default:return -EBADMSG;}if (cnt < pdulen)return -EBADMSG;switch (type) {case SYNC:timestamp_post_recv(m, &m->sync.originTimestamp);break;case DELAY_REQ:break;case PDELAY_REQ:break;case PDELAY_RESP:timestamp_post_recv(m, &m->pdelay_resp.requestReceiptTimestamp);port_id_post_recv(&m->pdelay_resp.requestingPortIdentity);break;case FOLLOW_UP:timestamp_post_recv(m, &m->follow_up.preciseOriginTimestamp);break;case DELAY_RESP:timestamp_post_recv(m, &m->delay_resp.receiveTimestamp);port_id_post_recv(&m->delay_resp.requestingPortIdentity);break;case PDELAY_RESP_FOLLOW_UP:timestamp_post_recv(m, &m->pdelay_resp_fup.responseOriginTimestamp);port_id_post_recv(&m->pdelay_resp_fup.requestingPortIdentity);break;case ANNOUNCE:clock_gettime(CLOCK_MONOTONIC, &m->ts.host);timestamp_post_recv(m, &m->announce.originTimestamp);announce_post_recv(&m->announce);break;case SIGNALING:port_id_post_recv(&m->signaling.targetPortIdentity);break;case MANAGEMENT:port_id_post_recv(&m->management.targetPortIdentity);break;}suffix_len = suffix_post_recv(m, cnt - pdulen);if (suffix_len < 0) {return suffix_len;}if (pdulen + suffix_len != m->header.messageLength) {return -EBADMSG;}return 0;
}
static void timestamp_post_recv(struct ptp_message *m, struct Timestamp *ts)
{uint32_t lsb = ntohl(ts->seconds_lsb);uint16_t msb = ntohs(ts->seconds_msb);m->ts.pdu.sec  = ((uint64_t)lsb) | (((uint64_t)msb) << 32);m->ts.pdu.nsec = ntohl(ts->nanoseconds);
}

把接受到的sync报文中t1放在hwt->ts->pdu里;

void process_sync(struct port *p, struct ptp_message *m)
{enum syfu_event event;switch (p->state) {case PS_INITIALIZING:case PS_FAULTY:case PS_DISABLED:case PS_LISTENING:case PS_PRE_MASTER:case PS_MASTER:case PS_GRAND_MASTER:case PS_PASSIVE:return;case PS_UNCALIBRATED:case PS_SLAVE:break;}if (check_source_identity(p, m)) {return;}if (!msg_unicast(m) &&m->header.logMessageInterval != p->log_sync_interval) {p->log_sync_interval = m->header.logMessageInterval;clock_sync_interval(p->clock, p->log_sync_interval);}m->header.correction += p->asymmetry;if (one_step(m)) {port_synchronize(p, m->header.sequenceId,m->hwts.ts, m->ts.pdu,m->header.correction, 0,m->header.logMessageInterval);flush_last_sync(p);return;}if (p->syfu == SF_HAVE_FUP &&fup_sync_ok(p->last_syncfup, m) &&p->last_syncfup->header.sequenceId == m->header.sequenceId) {event = SYNC_MATCH;} else {event = SYNC_MISMATCH;}port_syfufsm(p, event, m);
}
static void port_synchronize(struct port *p,uint16_t seqid,tmv_t ingress_ts,struct timestamp origin_ts,Integer64 correction1, Integer64 correction2,Integer8 sync_interval)
{enum servo_state state, last_state;tmv_t t1, t1c, t2, c1, c2;port_set_sync_rx_tmo(p);t1 = timestamp_to_tmv(origin_ts);t2 = ingress_ts;c1 = correction_to_tmv(correction1);c2 = correction_to_tmv(correction2);t1c = tmv_add(t1, tmv_add(c1, c2));switch (p->state) {case PS_UNCALIBRATED:case PS_SLAVE://记录t1,t2,还有修正域的和,为了延迟不对称或者有小数nsmonitor_sync(p->slave_event_monitor,clock_parent_identity(p->clock), seqid,t1, tmv_add(c1, c2), t2);break;default:break;}last_state = clock_servo_state(p->clock);//保持时钟的同步state = clock_synchronize(p->clock, t2, t1c);switch (state) {case SERVO_UNLOCKED:port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);if (servo_offset_threshold(clock_servo(p->clock)) != 0 &&sync_interval != p->initialLogSyncInterval) {p->logPdelayReqInterval = p->logMinPdelayReqInterval;p->logSyncInterval = p->initialLogSyncInterval;port_tx_interval_request(p, SIGNAL_NO_CHANGE,SIGNAL_SET_INITIAL,SIGNAL_NO_CHANGE);}break;case SERVO_JUMP:port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);flush_delay_req(p);if (p->peer_delay_req) {msg_put(p->peer_delay_req);p->peer_delay_req = NULL;}break;case SERVO_LOCKED:port_dispatch(p, EV_MASTER_CLOCK_SELECTED, 0);break;case SERVO_LOCKED_STABLE:message_interval_request(p, last_state, sync_interval);break;}
}
/*这里应该使用的是之前计算出的路径延迟,通过得到t1和t2可以计算出offset,再通过私服时钟保持从时钟和主时钟一致(伺服时钟的算法有很多可以进行选择)*/
enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin)
{enum servo_state state = SERVO_UNLOCKED;double adj, weight;int64_t offset;c->ingress_ts = ingress;tsproc_down_ts(c->tsproc, origin, ingress);//更新offset,保持时钟同步if (tsproc_update_offset(c->tsproc, &c->master_offset, &weight)) {if (c->free_running) {return clock_no_adjust(c, ingress, origin);} else {return state;}}if (clock_utc_correct(c, ingress)) {return c->servo_state;}/*当前从时钟与主时钟的差值*/c->cur.offsetFromMaster = tmv_to_TimeInterval(c->master_offset);if (c->free_running) {return clock_no_adjust(c, ingress, origin);}offset = tmv_to_nanoseconds(c->master_offset);adj = servo_sample(c->servo, offset, tmv_to_nanoseconds(ingress),weight, &state);c->servo_state = state;tsproc_set_clock_rate_ratio(c->tsproc, clock_rate_ratio(c));//伺服时钟是为了调整从时钟,为了保持和主时钟的一致性switch (state) {case SERVO_UNLOCKED:break;case SERVO_JUMP:clockadj_set_freq(c->clkid, -adj);clockadj_step(c->clkid, -tmv_to_nanoseconds(c->master_offset));c->ingress_ts = tmv_zero();if (c->sanity_check) {clockcheck_set_freq(c->sanity_check, -adj);clockcheck_step(c->sanity_check,-tmv_to_nanoseconds(c->master_offset));}tsproc_reset(c->tsproc, 0);break;case SERVO_LOCKED:clock_synchronize_locked(c, adj);break;case SERVO_LOCKED_STABLE:if (c->write_phase_mode) {clockadj_set_phase(c->clkid, -offset);adj = 0;} else {clock_synchronize_locked(c, adj);}break;}if (c->stats.max_count > 1) {clock_stats_update(&c->stats, tmv_dbl(c->master_offset), adj);} else {pr_info("master offset %10" PRId64 " s%d freq %+7.0f ""path delay %9" PRId64,tmv_to_nanoseconds(c->master_offset), state, adj,tmv_to_nanoseconds(c->path_delay));}return state;
}
static void port_syfufsm(struct port *p, enum syfu_event event,struct ptp_message *m)
{struct ptp_message *syn, *fup;/*接收到的sync时syfu为SF_EMPTY,事件为SYNC_MISMATCH,则后面为SF_HAVE_SYNC*/switch (p->syfu) {case SF_EMPTY:switch (event) {case SYNC_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case FUP_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case SYNC_MATCH:break;case FUP_MATCH:break;}break;case SF_HAVE_SYNC:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case SYNC_MATCH:break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case FUP_MATCH:syn = p->last_syncfup;port_synchronize(p, syn->header.sequenceId,syn->hwts.ts, m->ts.pdu,syn->header.correction,m->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;break;}break;case SF_HAVE_FUP:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case SYNC_MATCH:fup = p->last_syncfup;port_synchronize(p, fup->header.sequenceId,m->hwts.ts, fup->ts.pdu,m->header.correction,fup->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case FUP_MATCH:break;}break;}
}

上述为接受sync报文的过程;

void process_follow_up(struct port *p, struct ptp_message *m)
{enum syfu_event event;switch (p->state) {case PS_INITIALIZING:case PS_FAULTY:case PS_DISABLED:case PS_LISTENING:case PS_PRE_MASTER:case PS_MASTER:case PS_GRAND_MASTER:case PS_PASSIVE:return;case PS_UNCALIBRATED:case PS_SLAVE:break;}if (check_source_identity(p, m)) {return;}if (p->follow_up_info) {struct follow_up_info_tlv *fui = follow_up_info_extract(m);if (!fui)return;clock_follow_up_info(p->clock, fui);}if (p->syfu == SF_HAVE_SYNC &&p->last_syncfup->header.sequenceId == m->header.sequenceId) {event = FUP_MATCH;} else {event = FUP_MISMATCH;}port_syfufsm(p, event, m);
}
static void port_syfufsm(struct port *p, enum syfu_event event,struct ptp_message *m)
{struct ptp_message *syn, *fup;/*接收到的sync时syfu为SF_EMPTY,事件为SYNC_MISMATCH,则后面为SF_HAVE_SYNC*/switch (p->syfu) {case SF_EMPTY:switch (event) {case SYNC_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case FUP_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case SYNC_MATCH:break;case FUP_MATCH:break;}break;/*slave接受了follow则变成SF_HAVE_SYNC,FUP_MISMATCH*/case SF_HAVE_SYNC:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case SYNC_MATCH:break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case FUP_MATCH:syn = p->last_syncfup;port_synchronize(p, syn->header.sequenceId,syn->hwts.ts, m->ts.pdu,syn->header.correction,m->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;//这里清空,则又是一个循环break;}break;case SF_HAVE_FUP:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case SYNC_MATCH:fup = p->last_syncfup;port_synchronize(p, fup->header.sequenceId,m->hwts.ts, fup->ts.pdu,m->header.correction,fup->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case FUP_MATCH:break;}break;}
}
static void port_syfufsm(struct port *p, enum syfu_event event,struct ptp_message *m)
{struct ptp_message *syn, *fup;/*接收到的sync时syfu为SF_EMPTY,事件为SYNC_MISMATCH,则后面为SF_HAVE_SYNC*/switch (p->syfu) {case SF_EMPTY:switch (event) {case SYNC_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case FUP_MISMATCH:msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case SYNC_MATCH:break;case FUP_MATCH:break;}break;/*slave接受了follow则变成SF_HAVE_SYNC,FUP_MISMATCH*/case SF_HAVE_SYNC:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case SYNC_MATCH:break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_FUP;break;case FUP_MATCH:syn = p->last_syncfup;//这里syn->hwts.ts是指sync的接受事件,m->ts.pdu时钟是指报文的携带事件或者发送事件。port_synchronize(p, syn->header.sequenceId,syn->hwts.ts, m->ts.pdu,syn->header.correction,m->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;//这里清空,则又是一个循环break;}break;case SF_HAVE_FUP:switch (event) {case SYNC_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;p->syfu = SF_HAVE_SYNC;break;case SYNC_MATCH:fup = p->last_syncfup;port_synchronize(p, fup->header.sequenceId,m->hwts.ts, fup->ts.pdu,m->header.correction,fup->header.correction,m->header.logMessageInterval);msg_put(p->last_syncfup);p->syfu = SF_EMPTY;break;case FUP_MISMATCH:port_syfufsm_print_mismatch(p, event, m);msg_put(p->last_syncfup);msg_get(m);p->last_syncfup = m;break;case FUP_MATCH:break;}break;}
}

这里有个问题,会重新记录follow up携带的的值为t1,t2在port_synchronize函数中只使用syn->ts的接收时间。

int port_delay_request(struct port *p)
{struct ptp_message *msg;/* Time to send a new request, forget current pdelay resp and fup */if (p->peer_delay_resp) {msg_put(p->peer_delay_resp);p->peer_delay_resp = NULL;}if (p->peer_delay_fup) {msg_put(p->peer_delay_fup);p->peer_delay_fup = NULL;}if (p->delayMechanism == DM_P2P) {return port_pdelay_request(p);}msg = msg_allocate();if (!msg) {return -1;}/*组成1588的头*/msg->hwts.type = p->timestamping;msg->header.tsmt               = DELAY_REQ | p->transportSpecific;msg->header.ver                = PTP_VERSION;msg->header.messageLength      = sizeof(struct delay_req_msg);msg->header.domainNumber       = clock_domain_number(p->clock);msg->header.correction         = -p->asymmetry;msg->header.sourcePortIdentity = p->portIdentity;msg->header.sequenceId         = p->seqnum.delayreq++;msg->header.control            = CTL_DELAY_REQ;msg->header.logMessageInterval = 0x7f;if (p->hybrid_e2e) {struct ptp_message *dst = TAILQ_FIRST(&p->best->messages);msg->address = dst->address;msg->header.flagField[0] |= UNICAST;}/*利用socket组包和发包*/if (port_prepare_and_send(p, msg, TRANS_EVENT)) {pr_err("port %hu: send delay request failed", portnum(p));goto out;}if (msg_sots_missing(msg)) {pr_err("missing timestamp on transmitted delay request");goto out;}TAILQ_INSERT_HEAD(&p->delay_req, msg, list);return 0;
out:msg_put(msg);return -1;
}

发送delay_req报文;

三、step4:master->slave(接受delay_req和发送resp_报文)

static int process_delay_req(struct port *p, struct ptp_message *m)
{int err, nsm, saved_seqnum_sync;struct ptp_message *msg;nsm = port_nsm_reply(p, m);if (!nsm && p->state != PS_MASTER && p->state != PS_GRAND_MASTER) {return 0;}if (p->delayMechanism == DM_P2P) {pr_warning("port %hu: delay request on P2P port", portnum(p));return 0;}msg = msg_allocate();if (!msg) {return -1;}msg->hwts.type = p->timestamping;msg->header.tsmt               = DELAY_RESP | p->transportSpecific;msg->header.ver                = PTP_VERSION;msg->header.messageLength      = sizeof(struct delay_resp_msg);msg->header.domainNumber       = m->header.domainNumber;msg->header.correction         = m->header.correction;msg->header.sourcePortIdentity = p->portIdentity;msg->header.sequenceId         = m->header.sequenceId;msg->header.control            = CTL_DELAY_RESP;msg->header.logMessageInterval = p->logMinDelayReqInterval;/*把接受到的delay_req的时间赋值给delay_resp中的接收时间域*/msg->delay_resp.receiveTimestamp = tmv_to_Timestamp(m->hwts.ts);msg->delay_resp.requestingPortIdentity = m->header.sourcePortIdentity;if (p->hybrid_e2e && msg_unicast(m)) {msg->address = m->address;msg->header.flagField[0] |= UNICAST;msg->header.logMessageInterval = 0x7f;}if (nsm && net_sync_resp_append(p, msg)) {pr_err("port %hu: append NSM failed", portnum(p));err = -1;goto out;}err = port_prepare_and_send(p, msg, TRANS_GENERAL);if (err) {pr_err("port %hu: send delay response failed", portnum(p));goto out;}if (nsm) {saved_seqnum_sync = p->seqnum.sync;p->seqnum.sync = m->header.sequenceId;err = port_tx_sync(p, &m->address);p->seqnum.sync = saved_seqnum_sync;}
out:msg_put(msg);return err;
}

process_delay_req函数接受报文并发送delay_resp报文

四、step 4: slave接受delay_resp报文

void process_delay_resp(struct port *p, struct ptp_message *m)
{struct delay_resp_msg *rsp = &m->delay_resp;struct ptp_message *req;tmv_t c3, t3, t4, t4c;if (p->state != PS_UNCALIBRATED && p->state != PS_SLAVE) {return;}if (!pid_eq(&rsp->requestingPortIdentity, &p->portIdentity)) {return;}if (check_source_identity(p, m)) {return;}TAILQ_FOREACH(req, &p->delay_req, list) {if (rsp->hdr.sequenceId == ntohs(req->delay_req.hdr.sequenceId)) {break;}}if (!req) {return;}c3 = correction_to_tmv(m->header.correction);t3 = req->hwts.ts;t4 = timestamp_to_tmv(m->ts.pdu);t4c = tmv_sub(t4, c3);//记录delay_req的发送时间t3和接受时间t4monitor_delay(p->slave_event_monitor, clock_parent_identity(p->clock),m->header.sequenceId, t3, c3, t4);//计算路径延迟clock_path_delay(p->clock, t3, t4c);TAILQ_REMOVE(&p->delay_req, req, list);msg_put(req);if (p->logMinDelayReqInterval == rsp->hdr.logMessageInterval) {return;}if (msg_unicast(m)) {/* Unicast responses have logMinDelayReqInterval set to 0x7F. */return;}if (rsp->hdr.logMessageInterval < -10 ||rsp->hdr.logMessageInterval > 22) {pl_info(300, "port %hu: ignore bogus delay request interval 2^%d",portnum(p), rsp->hdr.logMessageInterval);return;}p->logMinDelayReqInterval = rsp->hdr.logMessageInterval;pr_notice("port %hu: minimum delay request interval 2^%d",portnum(p), p->logMinDelayReqInterval);port_set_delay_tmo(p);
}void clock_path_delay(struct clock *c, tmv_t req, tmv_t rx)
{tsproc_up_ts(c->tsproc, req, rx);//更新延迟if (tsproc_update_delay(c->tsproc, &c->path_delay))return;c->cur.meanPathDelay = tmv_to_TimeInterval(c->path_delay);if (c->stats.delay)stats_add_value(c->stats.delay, tmv_dbl(c->path_delay));
}int tsproc_update_delay(struct tsproc *tsp, tmv_t *delay)
{tmv_t raw_delay;if (tmv_is_zero(tsp->t2) || tmv_is_zero(tsp->t3))return -1;/*这里利用不同的计算延迟的方式,有原始的和过滤的*/raw_delay = get_raw_delay(tsp);tsp->filtered_delay = filter_sample(tsp->delay_filter, raw_delay);tsp->filtered_delay_valid = 1;pr_debug("delay   filtered %10" PRId64 "   raw %10" PRId64,tmv_to_nanoseconds(tsp->filtered_delay),tmv_to_nanoseconds(raw_delay));if (!delay) {return 0;}switch (tsp->mode) {case TSPROC_FILTER:case TSPROC_FILTER_WEIGHT:*delay = tsp->filtered_delay;break;case TSPROC_RAW:case TSPROC_RAW_WEIGHT:*delay = raw_delay;break;}return 0;
}tmv_t get_raw_delay(struct tsproc *tsp)
{tmv_t t23, t41, delay;/* delay = ((t2 - t3) * rr + (t4 - t1)) / 2 */t23 = tmv_sub(tsp->t2, tsp->t3);if (tsp->clock_rate_ratio != 1.0)t23 = dbl_tmv(tmv_dbl(t23) * tsp->clock_rate_ratio);t41 = tmv_sub(tsp->t4, tsp->t1);delay = tmv_div(tmv_add(t23, t41), 2);if (tmv_sign(delay) < 0) {pr_debug("negative delay %10" PRId64,tmv_to_nanoseconds(delay));pr_debug("delay = (t2 - t3) * rr + (t4 - t1)");pr_debug("t2 - t3 = %+10" PRId64, tmv_to_nanoseconds(t23));pr_debug("t4 - t1 = %+10" PRId64, tmv_to_nanoseconds(t41));pr_debug("rr = %.9f", tsp->clock_rate_ratio);}return delay;
}

这样就计算出延迟值。

【liunxptp协议栈详解第一部分】相关推荐

  1. IIS负载均衡-Application Request Route详解第一篇: ARR介绍

    IIS负载均衡-Application Request Route详解第一篇: ARR介绍   说到负载均衡,相信大家已经不再陌生了,本系列主要介绍在IIS中可以采用的负载均衡的软件:微软的Appli ...

  2. PD3.1详解 第一章EPR

    ** PD3.1详解 第一章EPR ** 各大厂商逐渐在推广PD3.1的方案:从苹果的第一款PD3.1的适配器开始,目前慢慢的各种应用场合应用,比如一些电动工具,大功率储能产品等等. 首先PD3.1增 ...

  3. TCP/IP详解--第一章

    说明:专栏中的内容是<TCP/IP详解>这本书,博主分享在此. 第1章概     述 1.1   引言 很多不同的厂家生产各种型号的计算机,它们运行完全不同的操作系统,但  TCP/IP协 ...

  4. 23.从0学ARM-网卡DM9000及uboot协议栈详解

    第二十三章 一.网卡 1. 概念 网卡是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件.由于其拥有MAC地址,因此属于OSI模型的第2层.它使得用户可以通过电缆或无线相互连接. 每一个网卡 ...

  5. devc 无法编译循环语句_鸡生蛋还是蛋生鸡?详解第一个编译器是怎么来的~

    详解编译器自举原理 不知道你有没有想过,某种编程语言的第一个编译器是怎么来的呢?这不就是"鸡生蛋,蛋生鸡"的问题吗? 先说最后的结论:任何一种语言的第一个编译器肯定是使用其他语言写 ...

  6. VB6.0 ActiveX 控件开发详解 [第一章:创建工程]

    前言 在CSDN的VB论坛上,我总是能够看见有人这样问"有没有这样的控件,一个列表框,每一个项前面有一个按钮"(这是例子),又或者见到这样:"怎么样做一个ActiveX控 ...

  7. 孙鑫VC++深入详解第一章学习笔记

    第一章 Windows程序内部运行机制 1.1 API和SDK API:Windows操作系统提供给应用程序编程的接口. SDK(软件开发包):用于开发的所有资源的集合. 1.2 窗口和句柄 窗口 句 ...

  8. C++-10种控制语句详解(第一种-if)

    if语句详解 对于可能发生的事情,我们平时经常会说"如果--,那么--".语文里,我们叫它条件复句."如果"之后的内容我们称为条件,当条件满足时,就会发生&qu ...

  9. CCNP中单区域OSPF详解(第一部分)

    1. OSPF特性综述 2. Ospf协议下运行的三种拓补结构 3. 广播型多路访问网络下的OSPF运行      1)路由器ID      2)指定路由器和备份指定路由器      3)DR和BDR ...

  10. H.264/AVC视频编解码技术详解 第一章 视频信息与压缩编码

    H.264/AVC视频编解码技术详解系列笔记 是对 H.264/AVC视频编解码技术详解 课程的学习 文章目录 人与世界的交互 视频信号的表示方法 视频压缩编码 视频信息为什么可以被压缩? 视频压缩编 ...

最新文章

  1. DT大数据梦工厂 第51讲
  2. TCP网络编程中connect()、listen()和accept()三者之间的关系
  3. linux操作系统中查找某个进程,在linux下查看有哪些操作系统进程正在使用某一个共享内存段...
  4. 【这些都不知道你就是个弟弟】Docker常用命令
  5. 01数据库、DBMS和SQL
  6. c/c++排坑(4) -- c/c++中返回局部变量
  7. 网络恶意营销账号猖獗,国家网信办出手了
  8. 基于Metronic的Bootstrap开发框架经验总结(11)--页面菜单的几种呈现方式
  9. android用户头像保存,Android的登陆注册(sharedpreferences和SQLite保存以及头像上传显示...
  10. python读取MNIST image数据
  11. 29 - Excel 图表与数据分析
  12. 数据拟合(excel)
  13. CCTV十集大型纪录片《华尔街》高速下载地址
  14. 图片尺寸放大不改变清晰度
  15. <第2.5个月>新店日记,shopee要投入多少钱?利润怎么样能赚钱吗好做吗?shopee孵化期考核
  16. 红星美羚育儿经:宝宝上火,是奶粉的祸?
  17. Android设置来电号码归属地
  18. 一个屌丝程序猿的人生(九十)
  19. 交换两个变量的值的swap函数
  20. 如何使用Python实现图像文字识别OCR

热门文章

  1. 重磅!中国首家互联网银行联手腾讯、华为各大APP,最高5万额度,疯狂提额100亿!!!...
  2. VMware 虚拟化中:厚置备延迟置零、厚置备置零、Thin Provision三个的区别
  3. 程序员面试金典(第 6 版)
  4. GraphQL Go,graphql基本知识,go-graphql使用
  5. Android获取手机存储空间大小
  6. 【Github资源大汇总】 - 王朋
  7. JS实现京东表单注册
  8. 微擎api.php,微擎支付api发起支付并验证
  9. docker file详细介绍
  10. python发微信给手机充值话费_微信充话费如何自定义金额?最低1元起充的技巧...