first working
This commit is contained in:
44
frametypes/__init__.py
Normal file
44
frametypes/__init__.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""Frame type implementations for packet analysis."""
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
from .overview import Overview
|
||||
from .chapter10 import Chapter10Stats
|
||||
from .ch10_analog import Ch10AnalogStats
|
||||
from .ch10_tmats import Ch10TMATSStats
|
||||
from .ch10_pcm import Ch10PCMStats
|
||||
from .ch10_time import Ch10TimeStats
|
||||
from .iena import IENAStats
|
||||
from .ptp import PTPStats
|
||||
from .ptp_sync import PTPSyncStats
|
||||
from .ptp_announce import PTPAnnounceStats
|
||||
from .ptp_delay import PTPDelayStats
|
||||
|
||||
__all__ = [
|
||||
'FrameTypeInterface',
|
||||
'Overview',
|
||||
'Chapter10Stats',
|
||||
'Ch10AnalogStats',
|
||||
'Ch10TMATSStats',
|
||||
'Ch10PCMStats',
|
||||
'Ch10TimeStats',
|
||||
'IENAStats',
|
||||
'PTPStats',
|
||||
'PTPSyncStats',
|
||||
'PTPAnnounceStats',
|
||||
'PTPDelayStats',
|
||||
]
|
||||
|
||||
# Registry of available frame type classes
|
||||
FRAME_TYPES = {
|
||||
'overview': Overview,
|
||||
'chapter10': Chapter10Stats,
|
||||
'ch10-analog': Ch10AnalogStats,
|
||||
'ch10-tmats': Ch10TMATSStats,
|
||||
'ch10-pcm': Ch10PCMStats,
|
||||
'ch10-time': Ch10TimeStats,
|
||||
'iena': IENAStats,
|
||||
'ptp': PTPStats,
|
||||
'ptp-sync': PTPSyncStats,
|
||||
'ptp-announce': PTPAnnounceStats,
|
||||
'ptp-delay': PTPDelayStats
|
||||
}
|
||||
BIN
frametypes/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/base.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/base.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ch10_analog.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ch10_analog.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ch10_pcm.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ch10_pcm.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ch10_time.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ch10_time.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ch10_tmats.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ch10_tmats.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/chapter10.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/chapter10.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/iena.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/iena.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/overview.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/overview.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ptp.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ptp.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ptp_announce.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ptp_announce.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ptp_delay.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ptp_delay.cpython-313.pyc
Normal file
Binary file not shown.
BIN
frametypes/__pycache__/ptp_sync.cpython-313.pyc
Normal file
BIN
frametypes/__pycache__/ptp_sync.cpython-313.pyc
Normal file
Binary file not shown.
29
frametypes/base.py
Normal file
29
frametypes/base.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
|
||||
class FrameTypeInterface(ABC):
|
||||
def __init__(self):
|
||||
self.name: str = ""
|
||||
self.frames_list = []
|
||||
self.bytes = 0
|
||||
|
||||
def get_name(self):
|
||||
"""Return the interface's name"""
|
||||
return self.name
|
||||
|
||||
@abstractmethod
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
"""Add a packet to the statistics."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
"""Return a dictionary of statistics for the tabular report."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
"""Return column definitions as [(column_name, format_spec), ...]"""
|
||||
pass
|
||||
56
frametypes/ch10_analog.py
Normal file
56
frametypes/ch10_analog.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Ch10AnalogStats(FrameTypeInterface):
|
||||
"""Chapter 10 Analog Data Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Chapter 10 Analog"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.channel_ids = set()
|
||||
self.sample_counts = defaultdict(int)
|
||||
self.data_gaps = 0
|
||||
self.overrange_count = 0
|
||||
self.underrange_count = 0
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, decode Ch10 analog headers
|
||||
# Extract channel ID, sample count, check for over/underrange
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Duration': round(duration, 3),
|
||||
'Channels': len(self.channel_ids),
|
||||
'Data Gaps': self.data_gaps,
|
||||
'Overrange': self.overrange_count,
|
||||
'Underrange': self.underrange_count,
|
||||
'Pkt/s': round(self.count / duration, 1) if duration > 0 else 0
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Channels', 'd'),
|
||||
('Data Gaps', 'd'),
|
||||
('Overrange', 'd'),
|
||||
('Underrange', 'd'),
|
||||
('Pkt/s', '.1f')
|
||||
]
|
||||
54
frametypes/ch10_pcm.py
Normal file
54
frametypes/ch10_pcm.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Ch10PCMStats(FrameTypeInterface):
|
||||
"""Chapter 10 PCM (Pulse Code Modulation) Data Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Chapter 10 PCM"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.channel_ids = set()
|
||||
self.frame_sync_errors = 0
|
||||
self.bit_slip_events = 0
|
||||
self.minor_frame_count = 0
|
||||
self.major_frame_count = 0
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, decode PCM frame structure
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Duration': round(duration, 3),
|
||||
'Channels': len(self.channel_ids),
|
||||
'Sync Errors': self.frame_sync_errors,
|
||||
'Bit Slips': self.bit_slip_events,
|
||||
'Minor Frames': self.minor_frame_count,
|
||||
'Major Frames': self.major_frame_count
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Channels', 'd'),
|
||||
('Sync Errors', 'd'),
|
||||
('Bit Slips', 'd'),
|
||||
('Minor Frames', 'd'),
|
||||
('Major Frames', 'd')
|
||||
]
|
||||
52
frametypes/ch10_time.py
Normal file
52
frametypes/ch10_time.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Ch10TimeStats(FrameTypeInterface):
|
||||
"""Chapter 10 Time Data Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Chapter 10 Time"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.time_sources = set()
|
||||
self.time_format_changes = 0
|
||||
self.leap_second_events = 0
|
||||
self.time_discontinuities = 0
|
||||
self.max_time_delta = 0
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, decode time packets
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Time Sources': len(self.time_sources),
|
||||
'Format Changes': self.time_format_changes,
|
||||
'Leap Seconds': self.leap_second_events,
|
||||
'Discontinuities': self.time_discontinuities,
|
||||
'Max Delta': round(self.max_time_delta, 6)
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Time Sources', 'd'),
|
||||
('Format Changes', 'd'),
|
||||
('Leap Seconds', 'd'),
|
||||
('Discontinuities', 'd'),
|
||||
('Max Delta', '.6f')
|
||||
]
|
||||
52
frametypes/ch10_tmats.py
Normal file
52
frametypes/ch10_tmats.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Ch10TMATSStats(FrameTypeInterface):
|
||||
"""Chapter 10 TMATS (Telemetry Attributes Transfer Standard) Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Chapter 10 TMATS"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.tmats_versions = set()
|
||||
self.configuration_changes = 0
|
||||
self.g_records = 0 # Data source records
|
||||
self.r_records = 0 # Tape/storage records
|
||||
self.m_records = 0 # Multiplexing/modulation records
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, parse TMATS records
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Versions': len(self.tmats_versions),
|
||||
'Config Changes': self.configuration_changes,
|
||||
'G-Records': self.g_records,
|
||||
'R-Records': self.r_records,
|
||||
'M-Records': self.m_records
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Versions', 'd'),
|
||||
('Config Changes', 'd'),
|
||||
('G-Records', 'd'),
|
||||
('R-Records', 'd'),
|
||||
('M-Records', 'd')
|
||||
]
|
||||
57
frametypes/chapter10.py
Normal file
57
frametypes/chapter10.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Chapter10Stats(FrameTypeInterface):
|
||||
"""General Chapter 10 Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Chapter 10"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.channel_ids = set()
|
||||
self.data_types = defaultdict(int)
|
||||
self.sequence_errors = 0
|
||||
self.last_sequence = {}
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# Simulate Chapter 10 specific processing
|
||||
# In real implementation, decode Chapter 10 headers
|
||||
if packet:
|
||||
# Example: extract channel ID and data type from payload
|
||||
# channel_id = extract_channel_id(packet)
|
||||
# data_type = extract_data_type(packet)
|
||||
# sequence = extract_sequence_number(packet)
|
||||
pass
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Duration': round(duration, 3),
|
||||
'Channels': len(self.channel_ids),
|
||||
'Seq Errors': self.sequence_errors,
|
||||
'Pkt/s': round(self.count / duration, 1) if duration > 0 else 0
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Channels', 'd'),
|
||||
('Seq Errors', 'd'),
|
||||
('Pkt/s', '.1f')
|
||||
]
|
||||
53
frametypes/iena.py
Normal file
53
frametypes/iena.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class IENAStats(FrameTypeInterface):
|
||||
"""IENA Protocol Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "IENA"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.key_fields = set()
|
||||
self.sequence_gaps = 0
|
||||
self.last_sequence = None
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# Simulate IENA specific processing
|
||||
if packet:
|
||||
# Example: extract IENA key field and sequence
|
||||
# key_field = extract_iena_key(packet)
|
||||
# sequence = extract_iena_sequence(packet)
|
||||
pass
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Duration': round(duration, 3),
|
||||
'Key Fields': len(self.key_fields),
|
||||
'Seq Gaps': self.sequence_gaps,
|
||||
'Pkt/s': round(self.count / duration, 1) if duration > 0 else 0
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Key Fields', 'd'),
|
||||
('Seq Gaps', 'd'),
|
||||
('Pkt/s', '.1f')
|
||||
]
|
||||
64
frametypes/overview.py
Normal file
64
frametypes/overview.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import statistics
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class Overview(FrameTypeInterface):
|
||||
def __init__(self):
|
||||
self.name = "Overview"
|
||||
self.count = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.Tdeltas = []
|
||||
self.bytes = 0
|
||||
self.frames_list = []
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
self.frames_list.append(packet)
|
||||
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
else:
|
||||
self.Tdeltas.append(timestamp - self.last_time)
|
||||
self.last_time = timestamp
|
||||
|
||||
@property
|
||||
def duration(self): return (self.last_time or 0) - (self.first_time or 0)
|
||||
@property
|
||||
def avg_size(self): return self.bytes / self.count if self.count else 0
|
||||
@property
|
||||
def avg_delta(self): return statistics.mean(self.Tdeltas) if self.Tdeltas else 0
|
||||
@property
|
||||
def std_delta(self): return statistics.stdev(self.Tdeltas) if len(self.Tdeltas) > 1 else 0
|
||||
@property
|
||||
def pkt_rate(self): return self.count / self.duration if self.duration > 0 else 0
|
||||
@property
|
||||
def byte_rate(self): return self.bytes / self.duration if self.duration > 0 else 0
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Bytes': self.bytes,
|
||||
'Duration': round(self.duration, 3),
|
||||
'Avg Size': round(self.avg_size, 1),
|
||||
'Avg TimeΔ': round(self.avg_delta, 6),
|
||||
'Time 1σ': round(self.std_delta, 6),
|
||||
'Pkt/s': round(self.pkt_rate, 1),
|
||||
'B/s': round(self.byte_rate, 1)
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Bytes', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Avg Size', '.1f'),
|
||||
('Avg Delta', '.6f'),
|
||||
('Std Delta', '.6f'),
|
||||
('Pkt/s', '.1f'),
|
||||
('B/s', '.1f')
|
||||
]
|
||||
56
frametypes/ptp.py
Normal file
56
frametypes/ptp.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class PTPStats(FrameTypeInterface):
|
||||
"""General PTP Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "PTP"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.sync_messages = 0
|
||||
self.follow_up_messages = 0
|
||||
self.delay_req_messages = 0
|
||||
self.delay_resp_messages = 0
|
||||
self.announce_messages = 0
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# Simulate PTP message type counting
|
||||
if packet:
|
||||
# Example: decode PTP message type
|
||||
# msg_type = extract_ptp_message_type(packet)
|
||||
pass
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Duration': round(duration, 3),
|
||||
'Sync': self.sync_messages,
|
||||
'Follow Up': self.follow_up_messages,
|
||||
'Delay Req': self.delay_req_messages,
|
||||
'Delay Resp': self.delay_resp_messages,
|
||||
'Announce': self.announce_messages
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Duration', '.3f'),
|
||||
('Sync', 'd'),
|
||||
('Follow Up', 'd'),
|
||||
('Delay Req', 'd'),
|
||||
('Delay Resp', 'd'),
|
||||
('Announce', 'd')
|
||||
]
|
||||
51
frametypes/ptp_announce.py
Normal file
51
frametypes/ptp_announce.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class PTPAnnounceStats(FrameTypeInterface):
|
||||
"""PTP Announce Message Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "PTP Announce"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.announce_count = 0
|
||||
self.grandmaster_changes = 0
|
||||
self.priority_changes = 0
|
||||
self.grandmaster_ids = set()
|
||||
self.clock_classes = defaultdict(int)
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, decode PTP announce messages
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Announce': self.announce_count,
|
||||
'GM Changes': self.grandmaster_changes,
|
||||
'Priority Changes': self.priority_changes,
|
||||
'Grandmasters': len(self.grandmaster_ids),
|
||||
'Clock Classes': len(self.clock_classes)
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Announce', 'd'),
|
||||
('GM Changes', 'd'),
|
||||
('Priority Changes', 'd'),
|
||||
('Grandmasters', 'd'),
|
||||
('Clock Classes', 'd')
|
||||
]
|
||||
53
frametypes/ptp_delay.py
Normal file
53
frametypes/ptp_delay.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import statistics
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class PTPDelayStats(FrameTypeInterface):
|
||||
"""PTP Delay Request/Response Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "PTP Delay"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.delay_req_count = 0
|
||||
self.delay_resp_count = 0
|
||||
self.pdelay_req_count = 0
|
||||
self.pdelay_resp_count = 0
|
||||
self.round_trip_times = []
|
||||
self.asymmetry_values = []
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, match delay requests with responses
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
avg_rtt = statistics.mean(self.round_trip_times) if self.round_trip_times else 0
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Delay Req': self.delay_req_count,
|
||||
'Delay Resp': self.delay_resp_count,
|
||||
'PDelay Req': self.pdelay_req_count,
|
||||
'PDelay Resp': self.pdelay_resp_count,
|
||||
'Avg RTT': round(avg_rtt * 1000, 3) # Convert to ms
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Delay Req', 'd'),
|
||||
('Delay Resp', 'd'),
|
||||
('PDelay Req', 'd'),
|
||||
('PDelay Resp', 'd'),
|
||||
('Avg RTT', '.3f')
|
||||
]
|
||||
58
frametypes/ptp_sync.py
Normal file
58
frametypes/ptp_sync.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import statistics
|
||||
from typing import Dict, List, Any
|
||||
from scapy.all import Packet
|
||||
|
||||
from .base import FrameTypeInterface
|
||||
|
||||
|
||||
class PTPSyncStats(FrameTypeInterface):
|
||||
"""PTP Sync Message Statistics"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "PTP Sync"
|
||||
self.count = 0
|
||||
self.bytes = 0
|
||||
self.first_time = None
|
||||
self.last_time = None
|
||||
self.sync_count = 0
|
||||
self.follow_up_count = 0
|
||||
self.two_step_count = 0
|
||||
self.one_step_count = 0
|
||||
self.sync_intervals = []
|
||||
self.clock_ids = set()
|
||||
|
||||
def add(self, timestamp: float, size: int, packet: Packet):
|
||||
self.count += 1
|
||||
self.bytes += size
|
||||
if self.first_time is None:
|
||||
self.first_time = timestamp
|
||||
else:
|
||||
if self.last_time and self.sync_count > 0:
|
||||
self.sync_intervals.append(timestamp - self.last_time)
|
||||
self.last_time = timestamp
|
||||
|
||||
# In real implementation, decode PTP sync messages
|
||||
|
||||
def get_summary_dict(self) -> Dict[str, Any]:
|
||||
duration = (self.last_time or 0) - (self.first_time or 0)
|
||||
avg_interval = statistics.mean(self.sync_intervals) if self.sync_intervals else 0
|
||||
return {
|
||||
'Pkts': self.count,
|
||||
'Sync Msgs': self.sync_count,
|
||||
'Follow-ups': self.follow_up_count,
|
||||
'Two-step': self.two_step_count,
|
||||
'One-step': self.one_step_count,
|
||||
'Clock IDs': len(self.clock_ids),
|
||||
'Avg Interval': round(avg_interval, 6)
|
||||
}
|
||||
|
||||
def get_column_definitions(self) -> List[tuple]:
|
||||
return [
|
||||
('Pkts', 'd'),
|
||||
('Sync Msgs', 'd'),
|
||||
('Follow-ups', 'd'),
|
||||
('Two-step', 'd'),
|
||||
('One-step', 'd'),
|
||||
('Clock IDs', 'd'),
|
||||
('Avg Interval', '.6f')
|
||||
]
|
||||
Reference in New Issue
Block a user