Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3.12 单播协商实现:PTP的“专线服务“

为什么需要单播

默认PTP使用组播,但有些场景需要单播:

组播的局限性:

1. 跨网段问题
   - 组播可能被路由器阻止
   - TTL限制传播范围
   - 需要组播路由支持

2. 网络负载
   - 所有设备都收到所有报文
   - 浪费带宽
   - 不必要的处理

3. 精确控制
   - 无法指定特定主时钟
   - 无法控制服务质量
   - 无法按需分配资源

单播的优势:

1. 跨网段
   - 穿越路由器
   - 无组播限制
   - 更广的覆盖范围

2. 按需服务
   - 只发送给请求者
   - 节省网络带宽
   - 精确控制目标

3. 服务质量
   - 可协商发送速率
   - 可协商持续时间
   - 灵活的参数配置

适用场景:
- 跨路由器的PTP
- 电信运营商网络
- 数据中心互联

单播协商协议

信令消息

单播协商使用Signaling消息:

Signaling Message结构:
┌─────────┬─────────┬──────────┬──────────┐
│Header   │Target   │TLV       │TLV       │
│34 bytes │Port ID  │(Request) │(Grant)   │
│         │10 bytes │Variable  │Variable  │
└─────────┴─────────┴──────────┴──────────┘

包含的TLV:
- REQUEST_UNICAST_TRANSMISSION
- GRANT_UNICAST_TRANSMISSION
- CANCEL_UNICAST_TRANSMISSION
- ACKNOWLEDGE_CANCEL_UNICAST_TRANSMISSION

协商流程

单播协商三步握手:

步骤1:请求(从时钟→ 主时钟)
Signaling消息包含:
- REQUEST_UNICAST_TRANSMISSION TLV
- messageType:请求的消息类型(Sync/Announce/Delay_Resp)
- logInterMessagePeriod:发送间隔
- durationField:请求的持续时间(秒)

步骤2:授权(主时钟 → 从时钟)
Signaling消息包含:
- GRANT_UNICAST_TRANSMISSION TLV
- messageType:同意的消息类型
- logInterMessagePeriod:实际发送间隔
- durationField:授权的持续时间
- flags:授权标志

步骤3:开始传输
主时钟按协商参数发送单播消息
从时钟接收并处理

步骤4:取消(可选)
任何一方可以发送CANCEL_UNICAST_TRANSMISSION
对方响应ACKNOWLEDGE_CANCEL_UNICAST_TRANSMISSION

TLV结构详解

REQUEST_UNICAST_TRANSMISSION

/* tlv.h, 第283-289行 */

struct request_unicast_xmit_tlv {
    Enumeration16type;              /* 0x0004 */
    UInteger16length;
    uint8_tmessage_type;            /* 请求的消息类型 */
    Integer8 logInterMessagePeriod; /* 发送间隔(log2秒) */
    UInteger32 durationField;       /* 持续时间(秒) */
};

消息类型编码

message_type字段:
bit 7-4:消息类型
bit 3-0:保留

编码:
0x10 = ANNOUNCE
0x20 = SYNC
0x40 = DELAY_RESP
0x50 = PDELAY_RESP

示例:
请求Sync消息:message_type = 0x20
请求Announce消息:message_type = 0x10

logInterMessagePeriod:
发送间隔 = 2^logInterMessagePeriod 秒

示例:
0:每1秒发送一次
-3:每0.125秒发送一次(125ms)
3:每8秒发送一次

GRANT_UNICAST_TRANSMISSION

/* tlv.h, 第169-177行 */

struct grant_unicast_xmit_tlv {
    Enumeration16 type;              /* 0x0005 */
    UInteger16 length;
    uint8_t message_type;            /* 消息类型 */
    Integer8 logInterMessagePeriod;  /* 发送间隔 */
    UInteger32 durationField;        /* 授权时长 */
    uint8_t reserved;
    uint8_t flags;                   /* 授权标志 */
};

flags字段

/* tlv.h, 第150行 */

#define GRANT_UNICAST_RENEWAL_INVITED (1 << 0)
flags含义:

bit 0:RENEWAL_INVITED
- 1:主时钟邀请从时钟续约
- 0:不邀请续约

续约流程:
1. 授权即将到期
2. 主时钟设置RENEWAL_INVITED = 1
3. 从时钟收到后可以提前请求续约
4. 避免服务中断

其他bits保留。

CANCEL_UNICAST_TRANSMISSION

/* tlv.h, 第162-167行 */

struct cancel_unicast_xmit_tlv {
    Enumeration16 type;         /* 0x0006 */
    UInteger16 length;
    uint8_t message_type_flags; /* 消息类型和标志 */
    uint8_t reserved;
};

取消流程

取消场景:

1. 从时钟不再需要服务
   - 断开连接
   - 切换到其他主时钟
   - 停止同步

2. 主时钟无法继续服务
   - 资源不足
   - 设备关闭
   - 配置变更

取消消息:
CANCEL_UNICAST_TRANSMISSION TLV
- message_type_flags:要取消的消息类型

确认消息:
ACKNOWLEDGE_CANCEL_UNICAST_TRANSMISSION TLV
- 确认收到取消请求
- 停止发送/接收

LinuxPTP实现

unicast_client结构

/* port.h中定义 */

struct unicast_client {
    LIST_ENTRY(unicast_client) list;
    struct PortIdentity portIdentity;   /* 目标端口ID */
    struct PortAddress address;          /* 目标地址 */
    uint8_t message_type;                /* 消息类型 */
    Integer8 logInterMessagePeriod;      /* 发送间隔 */
    UInteger32 durationField;            /* 剩余时长 */
    struct timespec grant_time;          /* 授权时间 */
    int state;                           /* 状态 */
};

发送请求

/* port.c中的单播请求(简化) */

static int port_request_unicast(struct port *p, struct unicast_client *client)
{
    struct ptp_message *msg;
    struct request_unicast_xmit_tlv *req;

    /* 构造Signaling消息 */
    msg = msg_allocate();
    msg->header.messageType = SIGNALING;
    
    /* 设置目标 */
    msg->signaling.targetPortIdentity = client->portIdentity;

    /* 构造REQUEST TLV */
    req = (struct request_unicast_xmit_tlv *) msg->management.suffix;
    req->type = TLV_REQUEST_UNICAST_TRANSMISSION;
    req->length = sizeof(*req) - sizeof(struct TLV);
    req->message_type = client->message_type;
    req->logInterMessagePeriod = client->logInterMessagePeriod;
    req->durationField = client->durationField;

    /* 字节序转换 */
    tlv_pre_send((struct TLV *)req, NULL);

    /* 发送 */
    return port_tx(p, msg, p->trp);
}

处理授权

/* port.c中的授权处理(简化) */

static void port_handle_grant(struct port *p, struct grant_unicast_xmit_tlv *grant)
{
    struct unicast_client *client;

    /* 字节序转换 */
    grant->durationField = ntohl(grant->durationField);

    /* 查找对应的请求 */
    client = find_unicast_client(p, grant->message_type);
    if (!client)
        return;

    /* 更新参数 */
    client->logInterMessagePeriod = grant->logInterMessagePeriod;
    client->durationField = grant->durationField;
    client->state = UNICAST_GRANTED;

    /* 记录授权时间 */
    clock_gettime(CLOCK_MONOTONIC, &client->grant_time);

    pr_info("unicast grant received: type %u, interval %d, duration %u",
            grant->message_type >> 4,
            client->logInterMessagePeriod,
            client->durationField);
}

发送单播消息

/* port.c中的单播发送(简化) */

static int port_tx_unicast(struct port *p, struct ptp_message *msg, 
                          struct unicast_client *client)
{
    /* 设置目标地址 */
    msg->address = client->address;

    /* 使用transport_sendto发送到特定地址 */
    return transport_sendto(p->trp, &p->fda, TRANS_EVENT, msg);
}

配置示例

从时钟配置

# /etc/linuxptp/ptp4l.conf

[global]
# 启用单播协商
unicast_nego_enabledefault1

# 单播主时钟表
unicast_master_tabletable1

[table1]
# 表索引
table_id 1

# 主时钟列表
logAnnounceInterval1
logSyncInterval   -3
logDelayReqInterval-3

# 主时钟地址
# 格式:addresspriority
master_address 192.168.1.100 128
master_address 192.168.1.101 127

[eth0]
# 使用单播主时钟表
unicast_master_tabletable1

主时钟配置

# /etc/linuxptp/ptp4l.conf

[global]
# 启用单播服务
unicast_nego_enabledefault1

# 允许单播请求
inhibit_multicast_service 0

[eth0]
# 主时钟优先级
priority1128
priority2128

启动命令

# 从时钟启动
ptp4l -i eth0 -f /etc/linuxptp/ptp4l.conf -m

# 主时钟启动
ptp4l -i eth0 -m -S

# 查看单播状态
pmc -u "GET UNICAST_MASTER_TABLE_NP"

单播 vs 组播对比

特性组播单播
地址224.0.1.129特定IP
覆盖范围子网内可跨网段
网络负载所有设备接收仅目标接收
配置复杂度简单较复杂
动态性自动发现需要协商
延迟测量E2E或P2PE2E
适用场景局域网广域网、跨网段

小结:单播协商的关键要点

核心概念

  • Signaling消息
  • 三步握手:请求→ 授权 → 传输

TLV类型

  • REQUEST_UNICAST_TRANSMISSION
  • GRANT_UNICAST_TRANSMISSION
  • CANCEL_UNICAST_TRANSMISSION
  • ACKNOWLEDGE_CANCEL_UNICAST_TRANSMISSION

协商参数

  • 消息类型
  • 发送间隔
  • 持续时间

适用场景

  • 跨网段PTP
  • 按需服务
  • 精确控制

下集预告

单播解决了“如何建立专线服务“,但网络中的故障如何诊断?

下一节,我们将分析故障处理与诊断——看看LinuxPTP如何应对各种故障场景。

【悬念留给3.13】

PTP网络中可能遇到各种故障。

如何检测链路故障?

如何处理主时钟丢失?

如何诊断同步问题?

下一节,最后一节源码分析。