关于使用linuxptp 最新的4.1版本,在X710 上使用 -H 硬件时钟打戳时,linuxptp的ptp4l报
received SYNC without timestamp
出现这个是因为ptp4l收到的报文没有hwts,也就是没有硬件的时间戳;
关于这部分的排查主要是找到代码中打印这句话的位置
if (msg_sots_missing(msg) &&
!(p->timestamping == TS_P2P1STEP && msg_type(msg) == PDELAY_REQ)) {
pr_err("%s: received %s without timestamp",
p->log_name, msg_type_string(msg_type(msg)));
msg_put(msg);
return EV_NONE;
}
其中
int msg_sots_missing(struct ptp_message *m)
{
int type = msg_type(m);
switch (type) {
case SYNC:
case DELAY_REQ:
case PDELAY_REQ:
case PDELAY_RESP:
break;
case FOLLOW_UP:
case DELAY_RESP://从这里可以看到 FOLLOW_UP和DELAY_RESP是不用验证的
case PDELAY_RESP_FOLLOW_UP:
case ANNOUNCE:
case SIGNALING:
case MANAGEMENT:
default:
return 0;
}
return msg_sots_valid(m) ? 0 : 1;
}
static inline int msg_sots_valid(struct ptp_message *m)
{
return !tmv_is_zero(m->hwts.ts);
}
static inline int tmv_is_zero(tmv_t x)
{
return x.ns == 0 ? 1 : 0; //这里是说ns数是不是0,如果有硬件时戳,就不是0
}
那么这个硬件时戳是哪来的呢?
msg = msg_allocate();
//申请内存
msg->hwts.type = p->timestamping;//时戳类型,如果执行时加了-H那就是硬件时戳TS_HARDWARE
cnt = transport_recv(p->trp, fd, msg);//就收UDP包
int transport_recv(struct transport *t, int fd, struct ptp_message *msg)
{
return t->recv(t, fd, msg, sizeof(msg->data), &msg->address, &msg->hwts);
}
static int udp_recv(struct transport *t, int fd, void *buf, int buflen,
struct address *addr, struct hw_timestamp *hwts)
{
return sk_receive(fd, buf, buflen, addr, hwts, MSG_DONTWAIT);
}
int sk_receive(int fd, void *buf, int buflen,
struct address *addr, struct hw_timestamp *hwts, int flags)
{
...
cnt = recvmsg(fd, &msg, flags);
...
for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
level = cm->cmsg_level;
type = cm->cmsg_type;
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);
}
}
...
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]);//给msg
break;
case TS_LEGACY_HW:
hwts->ts = timespec_to_tmv(ts[1]);
break;
}
}
在udp_recvmsg中会调用
sock_recv_ts_and_drops
->__sock_recv_ts_and_drops
->sock_recv_timestamp
->__sock_recv_timestamp
在__sock_recv_timestamp 会从skb中取shinfo中的hwtstamps
&skb_shinfo(skb)->hwtstamps
通过ktime_to_timespec_cond转换为 timespec类型
这里总共可以带出来3个时戳,因为 strcu scm_timestamping 定义了一个3个timespec类型元素的数组
1. soft类型的是 index 0 type是timestamp或者timestamps
2. hardware类型的是index 2 type是timestamping
而skb的hwtstamps是在网卡驱动中设置得,x710 是
i40e_process_skb_fields
->i40e_ptp_rx_hwtstamp
->i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb),ns);
但i40e_process_skb_fields 调用i40e_ptp_rx_hwtstamp 的条件是从 desc中获取到tsyncvalid标识,如果网卡的filter没有识别到ptp packet那么就不会置位,i40e驱动也就不会给skb打硬时戳。
那么linuxptp4.1 有什么不同呢,和2.0对比,他们发的SYNC报文 只有一个bit的差异,就是ptp version字段
因为linuxptp 4.1 版本支持了1588-2019 , 把PTP_VERSION设置为了2.1;
但x710 本身比1588-2019早,它不能识别2.1,所以就没有正确处理linuxptp 4.1 发的ptp报文
修改linuxptp 4.1 的PTP_MINOR_VERSION 为0 可以让i40e 给skb打hwstamp,但没细研究
PTP_MINOR_VERSION在linuxptp中的影响,先暂时测试用吧