Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions scapy/contrib/roce.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""
RoCE: RDMA over Converged Ethernet
"""

from scapy.layers.inet6 import IPv6
from scapy.packet import Packet, bind_layers, Raw
from scapy.fields import ByteEnumField, ByteField, XByteField, \
ShortField, XShortField, XLongField, BitField, XBitField, FCSField
Expand Down Expand Up @@ -157,30 +157,38 @@ def compute_icrc(self, p):
warning("Expecting UDP underlayer to compute checksum. Got %s.",
udp and udp.name)
return self.pack_icrc(0)

ip = udp.underlayer
if isinstance(ip, IP):
# pseudo-LRH / IP / UDP / BTH / payload
pshdr = Raw(b'\xff' * 8) / ip.copy()
# pseudo-LRH / IP / UDP / BTH / payload
pshdr = Raw(b'\xff' * 8) / ip.copy()
if isinstance(ip, IP): # IPv4
pshdr.chksum = 0xffff
pshdr.ttl = 0xff
pshdr.tos = 0xff
pshdr[UDP].chksum = 0xffff
pshdr[BTH].fecn = 1
pshdr[BTH].becn = 1
pshdr[BTH].resv6 = 0xff
bth = pshdr[BTH].self_build()
payload = raw(pshdr[BTH].payload)
# add ICRC placeholder just to get the right IP.totlen and
# UDP.length
icrc_placeholder = b'\xff\xff\xff\xff'
pshdr[UDP].payload = Raw(bth + payload + icrc_placeholder)
icrc = crc32(raw(pshdr)[:-4]) & 0xffffffff
return self.pack_icrc(icrc)

elif isinstance(ip, IPv6): # IPv6
pshdr.fl = 0xfffff
pshdr.tc = 0xff
pshdr.hlim = 0xff

else:
# TODO support IPv6
warning("The underlayer protocol %s is not supported.",
warning(f"The underlayer protocol %s is not supported.",
ip and ip.name)
return self.pack_icrc(0)
return struct.pack("!I", 0 & 0xffffffff)[::-1]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you not using pack_icrc(0) here?


pshdr[UDP].chksum = 0xffff
pshdr[BTH].fecn = 1
pshdr[BTH].becn = 1
pshdr[BTH].resv6 = 0xff
bth = pshdr[BTH].self_build()
payload = raw(pshdr[BTH].payload)

# add ICRC placeholder just to get the right IP.totlen and
# UDP.length
icrc_placeholder = b'\xff\xff\xff\xff'
pshdr[UDP].payload = Raw(bth + payload + icrc_placeholder)
icrc = crc32(raw(pshdr)[:-4]) & 0xffffffff
return self.pack_icrc(icrc)

# RoCE packets end with ICRC - a 32-bit CRC of the packet payload and
# pseudo-header. Add the ICRC header if it is missing and calculate its
Expand Down
27 changes: 27 additions & 0 deletions test/contrib/roce.uts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ assert pkt.opcode == CNP_OPCODE
del pkt.icrc
pkt = Ether(pkt.build())
assert pkt.icrc == 0x82fd002a
assert int(pkt[BTH].compute_icrc(pkt).hex(), 16) == pkt.icrc

= RoCE v1 RC RDMA WRITE ONLY

Expand Down Expand Up @@ -124,3 +125,29 @@ assert not pkt[BTH].ackreq
assert pkt[AETH].syndrome == 0
assert pkt[AETH].msn == 5
assert pkt.icrc == 0x25f0c038

= RoCE v2 RC ACKNOWLEDGE

pkt = Ether(import_hexcap('''\
0000 98 03 9b 99 51 3e 98 03 9b 99 51 42 81 00 60 00
0010 86 dd 60 e0 00 00 00 1c 11 80 20 00 00 11 02 37
0020 00 00 9a 03 9b ff fe 99 51 42 20 00 00 11 02 37
0030 00 00 9a 03 9b ff fe 99 51 3e c1 a2 12 b7 00 1c
0040 00 00 11 40 ff ff 00 00 0b af 00 08 0c 7b 00 00
0050 00 01 84 06 28 9a
'''))

assert BTH in pkt.layers()
assert AETH in pkt.layers()
assert pkt[IPv6].version == 6
assert pkt[IPv6].tc == 14
assert pkt[IPv6].fl == 0
assert pkt[IPv6].plen == 28
assert pkt[BTH].opcode == 0x11
assert pkt[BTH].padcount == 0
assert pkt[BTH].dqpn == 0x000baf
assert not pkt[BTH].ackreq
assert pkt[AETH].syndrome == 0
assert pkt[AETH].msn == 1
assert pkt.icrc == 0x8406289a
assert int(pkt[BTH].compute_icrc(pkt).hex(), 16) == pkt.icrc