Skip to content

Fix SCTP CRC32C computation under Python 3#210

Open
olibrius wants to merge 3 commits into
faucetsdn:masterfrom
olibrius:fix-sctp-crc32c-py3
Open

Fix SCTP CRC32C computation under Python 3#210
olibrius wants to merge 3 commits into
faucetsdn:masterfrom
olibrius:fix-sctp-crc32c-py3

Conversation

@olibrius
Copy link
Copy Markdown

Problem

ryu.lib.packet.sctp.sctp._checksum iterates str(data) and calls ord(c) on each character. In Python 2, str(bytes_obj) returned the raw bytes string, so the loop iterated the actual packet bytes. In Python 3, str(b'\x30\x39...') returns the repr "b'\\x30\\x39...'", so the CRC32C is computed over the ASCII representation of the bytes — not the bytes themselves.

Every SCTP packet serialized by Ryu under Python 3 therefore carries an invalid CRC32C and is dropped by SCTP-aware peers (Linux kernel, OVS, libsctp).

Fix

Iterate data directly (yields ints in Py3) and skip ord():

for b in data:
    crc32 = (crc32 >> 8) ^ crc_c[(crc32 ^ b) & 0xFF]

Verification

Known CRC32C test vector (RFC 3309 Appendix C.2):

CRC32C("123456789") = 0xe3069283

SCTP stores the value byte-swapped, so _checksum is expected to return 0x839206e3.

_checksum(b"123456789")
Before 0xc06ca59a
After 0x839206e3

End-to-end

Validated on Python 3.12 against OVS 3.1.0 with the in-tree ryu/tests/switch/tester.py on of13/action:

OK ERROR
Before 140 86
After 150 76

The 12 SCTP set_field failures are eliminated; remaining errors are unrelated (push_vlan / push_mpls header-init differences vs OVS, MPLS+ICMP test-fixture issues).

Note

This bug has been present since the original Python 2→3 migration. I have been running a Py3.11/3.12 fork (olibrius/ryu4312) that includes this fix and several other Py3.12 compatibility patches in production. Happy to split further patches into individual upstream PRs if useful — see the companion issue I am opening for the broader maintenance discussion.

olibrius and others added 3 commits May 14, 2026 10:41
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`ryu.lib.packet.sctp.sctp._checksum` iterated `str(data)` and called
`ord(c)` on each character. In Python 2, `str(bytes_obj)` returned the
raw bytes string, so the loop iterated the actual packet bytes. In
Python 3, `str(b'\x30\x39...')` returns the repr `"b'\\x30\\x39...'"`,
so the CRC32C is computed over the ASCII representation of the bytes
rather than the bytes themselves.

Effect: every SCTP packet serialized by Ryu carries a wrong CRC32C and
is therefore dropped by SCTP-aware peers (kernel, OVS, libsctp).

Verification (CRC32C of "123456789" per RFC 3309 Appendix C.2 = 0xe3069283;
SCTP stores the value byte-swapped):

    Before fix: Ryu _checksum("123456789") = 0xc06ca59a  (wrong)
    After  fix: Ryu _checksum("123456789") = 0x839206e3  (CRC32C swap of expected)

End-to-end validation against OVS 3.1.0:
    `ryu/tests/switch/of13/action`: 12 SCTP set_field failures eliminated
    (140 OK / 86 ERR -> 150 OK / 76 ERR).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant