From ef1be9ed6e7c5f6b11b8a1cea0a20e78837a35f4 Mon Sep 17 00:00:00 2001 From: Martin Teichmann <martin.teichmann@gmail.com> Date: Sun, 12 Feb 2023 10:45:21 +0000 Subject: [PATCH] avoid zero-lenght data in index datagram the anybus client does not like our index datagram with zero length data. While we are already at it, we also do proper padding according to the ethercat standard. Hopefully this way we are compatible with many more devices. --- ebpfcat/ebpfcat.py | 18 +++++++-------- ebpfcat/ethercat.py | 7 ++++-- ebpfcat/ethercat_test.py | 47 +++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/ebpfcat/ebpfcat.py b/ebpfcat/ebpfcat.py index a3a3c3d..7372199 100644 --- a/ebpfcat/ebpfcat.py +++ b/ebpfcat/ebpfcat.py @@ -260,36 +260,36 @@ class EtherXDP(XDP): counters = variables.globalVar("64I") rate = 0 + DATA0 = 26 def program(self): ETHERTYPE = 12 CMD0 = 16 - IDX0 = 17 ADDR0 = 18 with prandom(self.ebpf) & 0xffff < self.rate: self.dropcounter += 1 self.ebpf.exit(XDPExitCode.DROP) - with self.packetSize > 24 as p, p.pH[ETHERTYPE] == 0xA488, \ + with self.packetSize > 30 as p, p.pH[ETHERTYPE] == 0xA488, \ p.pB[CMD0] == 0: self.r3 = p.pI[ADDR0] # use r3 for tail_call with self.counters.get_address(None, False, False) as (dst, _), \ self.r3 < FastEtherCat.MAX_PROGS: self.r[dst] += 4 * self.r3 - self.r4 = self.mB[self.r[dst]] + self.r4 = self.mH[self.r[dst]] # we lost a packet - with p.pB[IDX0] == self.r4 as Else: + with p.pH[self.DATA0] == self.r4 as Else: self.mI[self.r[dst]] += 1 + (self.r4 & 1) # normal case: two packets on the wire - with Else, ((p.pB[IDX0] + 1 & 0xff) == self.r4) \ - | (p.pB[IDX0] == 0) as Else: + with Else, ((p.pH[self.DATA0] + 1 & 0xffff) == self.r4) \ + | (p.pH[self.DATA0] == 0) as Else: self.mI[self.r[dst]] += 1 with self.r4 & 1: # last one was active - p.pB[IDX0] = self.mB[self.r[dst]] + p.pH[self.DATA0] = self.mH[self.r[dst]] self.exit(XDPExitCode.TX) with Else: self.exit(XDPExitCode.PASS) - p.pB[IDX0] = self.mB[self.r[dst]] + p.pH[self.DATA0] = self.mH[self.r[dst]] self.r2 = self.get_fd(self.programs) self.call(FuncId.tail_call) self.exit(XDPExitCode.PASS) @@ -432,7 +432,7 @@ class FastSyncGroup(SyncGroupBase, XDP): await super().run() def update_devices(self, data): - if data[3] & 1: + if data[EtherXDP.DATA0 - Packet.ETHERNET_HEADER] & 1: self.current_data = data elif self.current_data is None: return self.asm_packet diff --git a/ebpfcat/ethercat.py b/ebpfcat/ethercat.py index b37b0a5..1e0b557 100644 --- a/ebpfcat/ethercat.py +++ b/ebpfcat/ethercat.py @@ -191,12 +191,13 @@ class Packet: """ MAXSIZE = 1000 # maximum size we use for an EtherCAT packet ETHERNET_HEADER = 14 + PACKET_HEADER = 16 DATAGRAM_HEADER = 10 DATAGRAM_TAIL = 2 def __init__(self): self.data = [] - self.size = 14 + self.size = self.PACKET_HEADER def append(self, cmd, data, idx, *address): """Append a datagram to the packet @@ -220,13 +221,15 @@ class Packet: An implicit empty datagram is added at the beginning of the packet that may be used as an identifier for the packet. """ - ret = [pack("<HBBiHHH", self.size | 0x1000, 0, 0, index, 1 << 15, 0, 0)] + ret = [pack("<HBBiHHHH", (self.size-2) | 0x1000, 0, 0, index, 0x8002, 0, 0, 0)] for i, (cmd, data, *dgram) in enumerate(self.data, start=1): ret.append(pack("<BBhHHH" if len(dgram) == 3 else "<BBiHH", cmd.value, *dgram, len(data) | ((i < len(self.data)) << 15), 0)) ret.append(data) ret.append(b"\0\0") + if self.size < 46: + ret.append(b"3" * (46 - self.size)) return b''.join(ret) def __str__(self): diff --git a/ebpfcat/ethercat_test.py b/ebpfcat/ethercat_test.py index 5c921c4..e6b93b4 100644 --- a/ebpfcat/ethercat_test.py +++ b/ebpfcat/ethercat_test.py @@ -123,30 +123,34 @@ class Tests(TestCase): ec.results = [None, None] await ti.initialize(-1, 4) ai = AnalogInput(ti.channel1.value) - SyncGroup.packet_index = 1000 + SyncGroup.packet_index = 0x66554433 sg = SyncGroup(ec, [ai]) self.task = sg.start() ec.expected = [ H("2a10" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram + "0000334455660280000000000000" # ID datagram # in datagram - "04000400801110000000000000000000000000000000000000000000"), - 1000, # == 0x3e8, see ID datagram + "04000400801110000000000000000000000000000000000000000000" + "3333"), # padding + 0x66554433, # index H("2a10" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram + "0000334455660280000000000000" # ID datagram # in datagram - "04000400801110000000123456780000000000000000000000000000"), - 1000, + "04000400801110000000123456780000000000000000000000000000" + "3333"), # padding + 0x66554433, # index ] ec.results = [ H("2a10" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram + "0000334455660280000000000000" # ID datagram # in datagram - "04000400801110000000123456780000000000000000000000000000"), + "04000400801110000000123456780000000000000000000000000000" + "3333"), # padding H("2a10" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram + "0000334455660280000000000000" # ID datagram # in datagram - "04000400801110000000123456780000000000000000000000000000"), + "04000400801110000000123456780000000000000000000000000000" + "3333"), # padding ] self.future = Future() with self.assertRaises(CancelledError): @@ -169,14 +173,15 @@ class Tests(TestCase): ec.results = [None, None] await ti.initialize(-2, 7) ao = AnalogOutput(ti.ch1_value) - SyncGroup.packet_index = 1000 + SyncGroup.packet_index = 0x55443322 sg = SyncGroup(ec, [ao]) self.task = sg.start() ec.expected = [ H("2210" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram - "0500070000110800000000000000000000000000"), # out datagram - 1000, # == 0x3e8, see ID datagram + "0000223344550280000000000000" # ID datagram + "0500070000110800000000000000000000000000" # out datagram + "33333333333333333333"), # padding + 0x55443322, # index ] ec.results = [ (8, 0), # return state 8, no error @@ -187,14 +192,16 @@ class Tests(TestCase): await gather(self.future, self.task) ec.expected = [ H("2210" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram - "0500070000110800000076980000000000000000"), # out datagram - 1000, + "0000223344550280000000000000" # ID datagram + "0500070000110800000076980000000000000000" # out datagram + "33333333333333333333"), # padding + 0x55443322, # index ] ec.results = [ H("2210" # EtherCAT Header, length & type - "0000e8030000008000000000" # ID datagram - "0500070000110800000076980000000000000000"), # out datagram + "0000223344550280000000000000" # ID datagram + "0500070000110800000076980000000000000000" # out datagram + "33333333333333333333"), # padding ] self.future = Future() with self.assertRaises(CancelledError): -- GitLab