Files
dtsstreaming/ptp_packet.py

87 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
PTP Packet class for IEEE1588 PTP frame parsing
"""
import struct
from typing import Dict, Optional
try:
from scapy.layers.inet import IP, UDP
except ImportError:
print("Error: scapy library not found. Install with: pip install scapy")
exit(1)
class PTPPacket:
"""Represents an IEEE1588 PTP packet"""
def __init__(self, packet):
"""
Initialize PTP packet from raw scapy packet
Args:
packet: Raw scapy packet
"""
self.raw_packet = packet
# Extract basic packet info
self.timestamp = float(packet.time)
# Extract IP/UDP info if available
if packet.haslayer(IP) and packet.haslayer(UDP):
ip_layer = packet[IP]
udp_layer = packet[UDP]
self.src_ip = ip_layer.src
self.dst_ip = ip_layer.dst
self.src_port = udp_layer.sport
self.dst_port = udp_layer.dport
self.payload = bytes(udp_layer.payload)
else:
self.src_ip = ""
self.dst_ip = ""
self.src_port = 0
self.dst_port = 0
self.payload = bytes()
# Parse PTP header
self.ptp_header = self._parse_ptp_header()
def _parse_ptp_header(self) -> Optional[Dict]:
"""Parse PTP header from payload"""
if len(self.payload) < 34: # Minimum PTP header size
return None
try:
message_type = self.payload[0] & 0x0F
version = (self.payload[1] >> 4) & 0x0F
message_length = struct.unpack('>H', self.payload[2:4])[0]
domain_number = self.payload[4]
flags = struct.unpack('>H', self.payload[6:8])[0]
correction_field = struct.unpack('>Q', self.payload[8:16])[0]
source_port_id = self.payload[20:30].hex()
sequence_id = struct.unpack('>H', self.payload[30:32])[0]
control_field = self.payload[32]
log_message_interval = struct.unpack('b', self.payload[33:34])[0]
message_types = {
0x0: 'Sync', 0x1: 'Delay_Req', 0x2: 'Pdelay_Req', 0x3: 'Pdelay_Resp',
0x8: 'Follow_Up', 0x9: 'Delay_Resp', 0xA: 'Pdelay_Resp_Follow_Up',
0xB: 'Announce', 0xC: 'Signaling', 0xD: 'Management'
}
return {
'message_type': message_types.get(message_type, f'Unknown({message_type})'),
'version': version,
'message_length': message_length,
'domain_number': domain_number,
'flags': f'0x{flags:04X}',
'correction_field': correction_field,
'source_port_id': source_port_id,
'sequence_id': sequence_id,
'control_field': control_field,
'log_message_interval': log_message_interval
}
except (struct.error, IndexError):
return None