PTP (IEEE 1588) 정밀 시각 동기화

PTP(Precision Time Protocol, IEEE 1588)는 이더넷 네트워크 내에서 나노초 수준의 시각 동기화를 달성하기 위한 표준 프로토콜입니다. TSN(Time-Sensitive Networking), 산업 자동화, 5G 프론트홀, 방송 미디어, 금융 거래 시스템에 핵심으로 쓰입니다. 리눅스 커널의 PTP 서브시스템(drivers/ptp/)은 NIC의 하드웨어 클럭(PHC)을 ptp_clock으로 노출하고, ptp4l/phc2sys 유저스페이스 툴이 클럭 계층 구성·보정·동기화를 담당합니다.

전제 조건: 이더넷ktime / Clock 문서를 먼저 읽으세요. PTP는 네트워크와 하드웨어 타이밍의 교차점입니다.
일상 비유: PTP는 정밀 전자 시계의 라디오 시각 동기화와 같습니다. 표준 시각 신호를 방송하는 Grandmaster(방송국)가 있고, 수신기들이 전파 지연 시간을 측정·보정하여 1초 이내가 아닌 나노초 이내로 시각을 맞춥니다.

핵심 요약

  • Grandmaster Clock — GPS나 원자 시계로부터 정확한 시각을 제공하는 최상위 클럭입니다.
  • Boundary Clock (BC) — 업스트림 포트는 슬레이브로 동기화하고, 다운스트림 포트로 시각을 재분배합니다. 네트워크 스위치에 구현됩니다.
  • Ordinary Clock (OC) — 단일 포트로 GM에 동기화되는 일반 호스트입니다.
  • PHC (PTP Hardware Clock) — NIC에 내장된 하드웨어 클럭 카운터로, TX/RX 타임스탬프를 나노초 해상도로 기록합니다.
  • ptp4l — PTP 프로토콜 상태 기계를 구현하는 유저스페이스 데몬입니다. PHC를 GM에 동기화합니다.
  • phc2sys — PHC와 시스템 클럭(CLOCK_REALTIME) 간 오프셋을 보정하는 데몬입니다.
  • gPTP (802.1AS) — IEEE 1588을 TSN 브리지에 맞게 프로파일링한 버전으로, 자동차(AUTOSAR) 및 오디오/비디오 브리징에 사용됩니다.
  • BMCA (Best Master Clock Algorithm) — 네트워크에서 가장 좋은 클럭 소스를 자동으로 선출하는 알고리즘입니다.

단계별 이해

  1. 하드웨어 요구사항 확인 — NIC가 하드웨어 타임스탬핑을 지원하는지(ethtool -T eth0) 확인합니다. 지원하지 않으면 소프트웨어 타임스탬프로 마이크로초 수준만 가능합니다.
  2. 클럭 계층 설계 — 네트워크 토폴로지에서 GM, BC, OC의 위치를 결정합니다.
  3. ptp4l로 PHC 동기화ptp4l -i eth0 -m으로 PHC를 GM에 동기화합니다.
  4. phc2sys로 시스템 클럭 동기화phc2sys -s eth0 -c CLOCK_REALTIME -m으로 CLOCK_REALTIME을 PHC에 동기화합니다.
  5. 정밀도 측정ptp4lmaster offset 로그로 나노초 오프셋과 주파수 보정량을 모니터링합니다.

IEEE 1588 프로토콜 개요

IEEE 1588은 2002년 제정(v1), 2008년 개정(v2), 2019년 확장(v2.1)된 네트워크 시각 동기화 표준입니다. 핵심 메커니즘은 지연 측정 + 오프셋 보정입니다.

동기화 메커니즘 (Delay Request-Response)

Grandmaster (GM) Slave (OC) ① Sync t1 ● ● t2 ② Follow_Up (t1 정밀값 포함, 2-step) ③ Delay_Req t3 ● ● t4 ④ Delay_Resp (t4 전달) 오프셋 = ((t2−t1) − (t4−t3)) / 2 지연 = ((t2−t1) + (t4−t3)) / 2

하드웨어 타임스탬핑을 사용하면 t1~t4를 NIC 레벨에서 기록하므로 소프트웨어 지터(OS 스케줄링 지연)가 제거됩니다. 일반 NTP의 마이크로초 정확도 대비 수십 나노초 정확도가 가능합니다.

클럭 유형과 계층

Grandmaster Clock GPS / 원자 시계 기반 (stratum 0) Boundary Clock 1 upstream slave + downstream master Boundary Clock 2 upstream slave + downstream master OC (Slave) End Device OC (Slave) End Device OC (Slave) End Device OC (Slave) End Device
클럭 유형설명포트 수
Grandmaster Clock (GM)GPS/원자 시계 기반 최상위 시각 소스1 (master)
Ordinary Clock (OC)단일 PTP 포트, 슬레이브 또는 마스터로 동작1
Boundary Clock (BC)업스트림 슬레이브 + 다운스트림 마스터(들)2+
Transparent Clock (TC)체류 시간(residence time)을 보정하는 스위치다수
End-to-End TC (E2ETC)전체 경로 지연 측정 지원 TC다수

리눅스 PTP 서브시스템

리눅스 커널의 PTP 서브시스템(drivers/ptp/ptp_clock.c)은 NIC 드라이버가 PHC(PTP Hardware Clock)를 /dev/ptp0와 같은 문자 디바이스로 노출하는 표준 인터페이스를 제공합니다.

ptp_clock_ops 구조체

/* include/linux/ptp_clock_kernel.h */
struct ptp_clock_ops {
    /* 필수 */
    int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm);
    int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
    int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
    int (*settime64)(struct ptp_clock_info *ptp,
                     const struct timespec64 *ts);

    /* 선택 — 하드웨어 타임스탬프 큐 */
    int (*getcrosststamp)(struct ptp_clock_info *ptp,
                          struct system_device_crosststamp *cts);

    /* Pulse Per Second / 외부 타임스탬프 / 주기적 출력 */
    int (*enable)(struct ptp_clock_info *ptp,
                  struct ptp_clock_request *request, int on);
};

ptp_clock_info 선언

static struct ptp_clock_info my_nic_ptp_info = {
    .owner      = THIS_MODULE,
    .name       = "my_nic PHC",
    .max_adj    = 500000,   /* 최대 주파수 보정량 (ppb) */
    .n_ext_ts   = 0,        /* 외부 타임스탬프 입력 수 */
    .n_per_out  = 0,        /* 주기적 출력 수 */
    .n_pins     = 0,        /* 재구성 가능한 핀 수 */
    .pps        = 1,        /* PPS (Pulse Per Second) 지원 */
    .adjfine    = my_nic_ptp_adjfine,
    .adjtime    = my_nic_ptp_adjtime,
    .gettime64  = my_nic_ptp_gettime,
    .settime64  = my_nic_ptp_settime,
    .enable     = my_nic_ptp_enable,
    .getcrosststamp = my_nic_ptp_getcrosststamp,
};

핵심 ops 구현

static int my_nic_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
    struct my_nic_priv *priv = container_of(ptp, struct my_nic_priv, ptp_info);
    s64 adj;
    u32 diff, incval;

    /* scaled_ppm은 65536 * ppm 단위 */
    adj = (s64)scaled_ppm * MY_NIC_CLK_PERIOD_NS;
    adj = div_s64(adj, 65536);

    incval = MY_NIC_CLK_BASE_INCVAL + (s32)adj;
    iowrite32(incval, priv->base + MY_NIC_REG_TIMADJ);
    return 0;
}

static int my_nic_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
    struct my_nic_priv *priv = container_of(ptp, struct my_nic_priv, ptp_info);
    unsigned long flags;

    spin_lock_irqsave(&priv->ptp_lock, flags);
    iowrite32((u32)(delta >> 32), priv->base + MY_NIC_REG_TIMEADJ_H);
    iowrite32((u32)(delta & 0xFFFFFFFF), priv->base + MY_NIC_REG_TIMEADJ_L);
    iowrite32(MY_NIC_CMD_ADJTIME, priv->base + MY_NIC_REG_CMD);
    spin_unlock_irqrestore(&priv->ptp_lock, flags);
    return 0;
}

static int my_nic_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
    struct my_nic_priv *priv = container_of(ptp, struct my_nic_priv, ptp_info);
    unsigned long flags;
    u64 ns;

    spin_lock_irqsave(&priv->ptp_lock, flags);
    /* 래치 명령으로 현재 시각 캡처 */
    iowrite32(MY_NIC_CMD_LATCH, priv->base + MY_NIC_REG_CMD);
    ns  = (u64)ioread32(priv->base + MY_NIC_REG_TIME_H) << 32;
    ns |= ioread32(priv->base + MY_NIC_REG_TIME_L);
    spin_unlock_irqrestore(&priv->ptp_lock, flags);

    *ts = ns_to_timespec64(ns);
    return 0;
}

PHC 등록과 해제

/* probe에서 */
priv->ptp_clock = ptp_clock_register(&priv->ptp_info, &pdev->dev);
if (IS_ERR(priv->ptp_clock)) {
    dev_err(&pdev->dev, "ptp_clock_register failed\n");
    priv->ptp_clock = NULL;
}

/* remove에서 */
if (priv->ptp_clock)
    ptp_clock_unregister(priv->ptp_clock);

linuxptp 유저스페이스 도구

ptp4l — PTP 프로토콜 데몬

ptp4l은 PTP 프로토콜 상태 기계(BMCA, 메시지 교환)를 구현하고 PHC를 GM에 동기화합니다.

# 기본 실행 (하드웨어 타임스탬프, eth0)
ptp4l -i eth0 -m

# 설정 파일 기반 (권장)
ptp4l -f /etc/linuxptp/ptp4l.conf -m

# 소프트웨어 타임스탬프 (HW 미지원 시)
ptp4l -i eth0 -m -S

# Slave only 모드 (GM이 될 수 없는 장치)
ptp4l -i eth0 -m -s
# /etc/linuxptp/ptp4l.conf
[global]
tx_timestamp_timeout  10
logMinDelayReqInterval -6
logSyncInterval        -4
domainNumber           0
slaveOnly              1
time_stamping          hardware
transportSpecific      0x0

[eth0]

phc2sys — PHC↔시스템 클럭 동기화

# PHC → CLOCK_REALTIME 동기화
phc2sys -s eth0 -c CLOCK_REALTIME -m -O 0

# 또는 PHC 인덱스로 직접 지정
phc2sys -s /dev/ptp0 -c CLOCK_REALTIME -m

# TAI 시각 오프셋 설정 (GPS 기반 GM에서 TAI↔UTC 차이)
phc2sys -s eth0 -c CLOCK_REALTIME -m -O -37

# 시스템 클럭 → PHC (반대 방향, Grandmaster 역할)
phc2sys -s CLOCK_REALTIME -c eth0 -m

pmc — PTP Management Client

# 포트 상태 확인
pmc -u -b 0 'GET PORT_DATA_SET'

# 현재 클럭 정보
pmc -u -b 0 'GET CURRENT_DATA_SET'

# GM 정보
pmc -u -b 0 'GET PARENT_DATA_SET'

# 시각 프로퍼티 (UTC 오프셋, 윤초 등)
pmc -u -b 0 'GET TIME_PROPERTIES_DATA_SET'

GPS Grandmaster 설정 (ts2phc)

ts2phc는 GPS PPS 신호를 사용하여 PHC를 GPS 시각에 동기화하고 Grandmaster 역할을 수행합니다.

# GPS PPS를 /dev/ptp0에 동기화
ts2phc -f /etc/linuxptp/ts2phc.conf -m

# ts2phc + ptp4l 동시 운용 (GM 구성)
ts2phc -f /etc/ts2phc.conf -m &
ptp4l -f /etc/ptp4l-master.conf -m &
# /etc/linuxptp/ts2phc.conf
[global]
use_syslog      1
verbose         1
time_stamp_mode=L

[eth0]
ts2phc.master   1   # 이 포트가 GM

[/dev/ptp_pps0]
ts2phc.master   0   # GPS PPS 입력

PTP 프로파일 변종

프로파일표준주요 용도정밀도
Default ProfileIEEE 1588-2019일반 네트워크~100ns
gPTP (802.1AS)IEEE 802.1AS-2020TSN, 자동차, AV 브리징<1μs
ITU-T G.8275.1ITU-T G.8275통신 네트워크 (5G 프론트홀)±30ns
ITU-T G.8275.2ITU-T G.8275부분 타임스탬프 네트워크±1.5μs
SMPTE ST 2059-2SMPTE방송 미디어방송 동기 수준

커널 내 PTP 클럭 API

커널 드라이버에서 PHC 시각을 직접 읽거나 비교할 때 사용합니다.

#include <linux/ptp_clock_kernel.h>

/* PHC 인덱스로 ptp_clock 획득 */
struct ptp_clock *ptp_clock;
ptp_clock = ptp_clock_get(phc_index);

/* 시스템 클럭과 PHC의 교차 타임스탬프 */
struct system_device_crosststamp cts;
ret = get_device_system_crosststamp(ptp_getcrosststamp, ptp_info,
                                    NULL, &cts);
/* cts.device: PHC 타임스탬프, cts.sys_realtime: 동시 CLOCK_REALTIME */

동기화 품질 검증

PTP 동기화 품질은 주로 master offsetpath delay의 두 지표로 평가합니다. ptp4l의 로그에서 master offset은 로컬 PHC와 Grandmaster 사이의 시각 차이(나노초)를 나타내고, freq는 발진기 주파수 보정량(ppb)을 의미합니다. 안정적인 하드웨어 타임스탬핑 환경에서는 offset이 수십~수백 나노초 범위를 유지합니다. 수 마이크로초를 초과하거나 진동이 크면 네트워크 체류 시간 변동(지터) 또는 PHC 발진기 품질 문제를 의심합니다.

# ptp4l 실시간 로그에서 오프셋 모니터링
# master offset: GM과의 오프셋(ns), s2: 2step sync
# freq: 주파수 보정량(ppb), path delay: 경로 지연(ns)
# ptp4l[12345.678]: master offset        -42 s2 freq   -1543 path delay    2312

# PHC 시각 직접 확인
phc_ctl /dev/ptp0 get

# PHC와 CLOCK_REALTIME 오프셋
phc_ctl /dev/ptp0 cmp

# 나노초 오프셋 히스토그램 (long-term 통계)
ts2phc -m 2>&1 | grep offset | awk '{print $NF}' | sort -n | uniq -c

TSN과 PTP 통합

IEEE 802.1Qbv(Time-Aware Shaper), 802.1Qbu(Frame Preemption) 등 TSN 표준은 PTP로 정의된 공통 시각을 사용하여 패킷 전송 창(transmission window)을 열고 닫습니다.

# TSN TAS (Time-Aware Shaper) 설정 예 (tc taprio)
tc qdisc replace dev eth0 parent root handle 100 taprio \
   num_tc 4 \
   map 0 1 2 3 0 0 0 0 \
   queues 1@0 1@1 1@2 1@3 \
   base-time 1000000000 \
   sched-entry S 0x8 200000 \   # 큐 3 개방 200μs
   sched-entry S 0x4 300000 \   # 큐 2 개방 300μs
   sched-entry S 0xF 500000 \   # 모든 큐 개방 500μs
   clockid CLOCK_TAI            # TAI 기반 스케줄

One-Step 타임스탬핑

2-step PTP는 Sync 후 Follow_Up을 별도 패킷으로 전송하여 t1을 전달합니다. One-step 타임스탬핑은 NIC 하드웨어가 Sync 패킷이 전선에 나가는 순간 패킷 내부에 직접 타임스탬프를 기록하므로 Follow_Up이 필요 없습니다. 패킷 수와 지터가 절반으로 줄어듭니다.

항목2-StepOne-Step
Sync 패킷 이후Follow_Up 별도 전송Follow_Up 불필요
t1 기록 위치Follow_Up 페이로드Sync 패킷 originTimestamp 필드 (NIC가 직접 기록)
패킷 수많음적음
하드웨어 요구사항TX 타임스탬프 읽기TX 패킷 내용 수정 능력 (egress edit)
Linux 지원표준 HW TSHWTSTAMP_TX_ONESTEP_SYNC
/* One-step TX 타임스탬프 모드 설정 */
struct hwtstamp_config cfg = {
    .tx_type   = HWTSTAMP_TX_ONESTEP_SYNC,  /* one-step */
    .rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
};

struct ifreq ifr;
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
ifr.ifr_data = (char *)&cfg;
ioctl(sock, SIOCSHWTSTAMP, &ifr);
ptp4l 설정: /etc/ptp4l.conf에서 tx_timestamp_timeout 1을 설정하고 NIC가 one-step을 지원하는 경우 one_step_sync 1을 활성화합니다.

IEEE 1588-2019 (v2.1) 주요 개선

2019년 발표된 v2.1(IEEE 1588-2019)은 v2(2008) 대비 아래 기능을 추가했습니다.

기능설명
CMLDS (Common Mean Link Delay Service)여러 PTP 인스턴스가 동일 링크의 지연 측정값을 공유
Enhanced Accuracy TLV클럭 정확도를 서브-나노초 단위로 전달
Port State Decision (PSDN)경로 선택 알고리즘 개선
Alternate Master결함 내성을 위한 다중 마스터 동시 추적
Signaling TLV 확장로그 주기·임계값 동적 협상
# ptp4l에서 v2.1 CMLDS 활성화 (linuxptp 3.x+)
# /etc/ptp4l.conf
[global]
dataset_comparison      ieee1588  # v2.1 데이터셋 비교 알고리즘
G.8275.defaultDS.localPriority 128
boundary_clock_jbod     1         # Boundary Clock JBOD 모드
cmlds                   1         # CMLDS 활성화
관련 페이지: 하드웨어 타임스탬핑 — NIC 레벨 타임스탬핑 구현 상세, 이더넷 — 네트워크 드라이버 기초, ktime / Clock — 커널 시각 서브시스템

문제 해결

증상원인해결
오프셋이 수백 μs 이상소프트웨어 타임스탬핑 사용ethtool -T eth0으로 HW 타임스탬핑 확인
ptp4l LISTENING 상태 고착PTP 패킷이 방화벽에 차단UDP 319/320 포트 허용
phc2sys 오프셋 발산TAI/UTC 오프셋 불일치-O 옵션으로 TAI-UTC 차이(37초) 설정
TX 타임스탬프 타임아웃드라이버 TX TS 지원 불완전tx_timestamp_timeout 값 증가
gPTP 동기화 실패802.1AS 요구 사항 미충족transportSpecific 0x1, peer delay 활성화