Repository navigation
feat(internet): implement IGMPv3 - #2465
Conversation
|
This implements IGMPv1/v2/v3 all in one Also: this PR touches Holding this for re-architecture once #2444's split lands. Unblocks when #2444 merges. |
a3537bb to
93c4c71
Compare
|
Coverage: 94.46% (unit tier, Python 3.15,
Per-file detail: the |
|
CI confirms the conflict already flagged: every Python version fails. Real defects, not flakes —
Holding this rather than dispatching a fix: #2444 is mid-redesign into split |
93c4c71 to
28fca7a
Compare
|
NEEDS CHANGES (Sonnet,
|
28fca7a to
40b839c
Compare
|
NEEDS CHANGES (Sonnet,
|
40b839c to
4b5e62d
Compare
4b5e62d to
988c4cc
Compare
|
Good-to-go CI watch caught a red check on Root cause: this branch's own pin (36) was self-consistent on its own base, but main has since gained the ARPHRD crawler (#2497), and this branch's own Patch outside the pin is unchanged -- rebased cleanly onto |
|
Decision needed: how to reconcile IGMPv3's design with main's already-merged IGMP v1/v2 (#2444). Context: this branch was built before #2444 existed, as a single concrete One thing favors a path forward: main's own Options:
Recommendation: option 1. It extends an already-merged, already-reviewed pattern rather than unwinding a settled decision on |
- IGMPv1/v2 messages and an IGMPv3 Membership Query share one GroupBody schema; a Query of at least 12 octets (RFC 3376 7.1) appends a QueryExtension (Resv/S Flag/QRV, QQIC, source list). - An IGMPv3 Membership Report (0x22) gets a ReportBody schema: a group record list covering the six RFC 3376 4.2.12 record types. Octets past the last record (Additional Data) stay as payload. - Max Resp Code and QQIC decode RFC 3376 4.1.1's floating-point encoding for codes >= 128. Reserved bits round-trip byte-exact. - IGMP.length is never below the 8-octet fixed header, so a cut header falls back to Raw instead of zero-filled fields. - Adds Type and RecordType const enumerations, exported from pcapkit.const, and wires IGMP into the Internet dispatch table. - A GroupBody unpacked on its own reads the extension by length alone. - The round-trip harness applies its overrides before selectors read them; IGMP's minimal type is pinned to a Query, since type 0 is reserved.
An earlier rebase left stray text and fused lines in 3 test files: - tests/protocols/test_dispatch_registry_unit.py had this PR's own commit-message fragment '(feat(internet): implement IGMPv3 (#2448))' pasted into two string literals. - tests/const/test_const_enum_get.py and test_const_enum_lookup.py each had a pin assertion fused onto the following statement on one line, with a blank line dropped before the next def. Dropped the stray text, split the fused lines, restored the blank lines. IGMP adds 2 const modules (igmp/type.py, igmp/record_type.py), but the pin bumps across all 4 census test files were only +1. Bumped the remaining +1 everywhere: ints 118->119, enums 134->135, distinct modules 128->129 (test_const_enum_builtin_parity); enums 124->125, covered 121->122 (test_const_enum_get); enums 118->119 (test_const_enum_lookup); all_files 128->129, generated 111->112 (test_const_registry_protocol). Verified: tests/const/, tests/vendor/, test_dispatch_registry_unit.py and test_igmp_unit.py all pass clean (630 tests, 26998 subtests).
…e literal A separate conflict-merge bug from the all.py/test-corruption rounds already fixed: pep.rst re-listed LINUX_SLL/LINUX_SLL2 as outstanding in three places (the Link Layer list, the real-capture-gaps sentence, and the wave-2 intro paragraph) even though main dropped them once #2443 landed, and even though this same file's own 'Done ahead of wave 2' section already describes them as implemented one page later. Restored all three to match main; kept IGMP's wording, which this branch had already gotten right. Also fixed a bare dpkt/pyshark literal in reassembly-integration.rst that predates this branch's fork point (main fixed it in 2f6c333, after this branch forked) -- same one-line fix, applied directly rather than rebasing. Rebased onto main (57ff1c8, the ARPHRD crawler merge): bumped EXPECTED_CRAWLERS_WITH_CONSTANT_MISS_LINES 36->37 in tests/vendor/test_vendor_missing_body_unit.py -- main's ARPHRD crawler accounts for one, this branch's own igmp/record_type.py crawler for the other, confirmed against the real crawler count on both the standalone branch (36, self-consistent) and the merged tree (37). Verified: test_conventions_doc_claims.py and test_docs_epilog_links_1936_unit.py pass clean (44 tests, 259 subtests); tests/vendor/ and tests/const/ pass clean after the rebase (580 tests, 26693 subtests).
Full-suite verification after the IGMPv3 sibling-class rebase (previous two commits) found four real issues the squashed merge introduced or left unresolved: - `pcapkit/protocols/data/__init__.py` and `.../schema/__init__.py`: the top-level `__all__` lists still carried a duplicate `'IGMP'` entry plus the old single-class design's names (`IGMP_GroupAddressMessage`, `IGMP_GroupBody`, etc.), which no longer exist. Replaced with the sibling names (`IGMPv3`, `IGMPv3_Query`, `IGMPv3_Report`, `IGMPv3_GroupRecord`, and the schema equivalents). - `pcapkit/protocols/internet/igmpv3.py`: import block was isort-dirty under the project's actual `-l100 -ppcapkit` Makefile flags. - `tests/project/test_rfc_constants_one_home_1739_unit.py`: the new `_classify` literal `12` (IGMPv3's minimum extended-Query length) coincidentally matches `AH_HEADER_LEN`/`TCP_DATA_OFFSET_OCTET`/ `GENERIC_BLOCK_MINIMUM`; added an `UNRELATED` entry explaining why. - `tests/protocols/internet/test_igmp_unit.py`: `test_refusals_name_the_version_refused` used an 8-octet *Report* fixture to probe IGMPv3's rejection path, but a Report type isn't Query-shaped at all, so IGMPv3's schema selector refuses it with "unsupported message type" rather than the `read()`-level "is not an IGMPv3 message" message the test expected. Switched to an 8-octet *Query* fixture, which is the shape all three versions actually share. Verified: `tests/protocols/internet/test_igmp_unit.py` (66 tests, 231 subtests), `tests/const/` + `tests/vendor/` + `test_dispatch_registry_unit.py` (588 tests, 26811 subtests), `tests/corekit/test_schema_roundtrip_unit.py` + `tests/project/` (2137 passed, 80 skipped, 0 failed, 11528 subtests) all clean.
1afc892 to
66317ed
Compare
|
Option 1 executed: IGMPv3 added as a concrete sibling, test suite rewritten for three classes. Old head What changedThe branch's own
|
| Suite | Result |
|---|---|
tests/protocols/internet/test_igmp_unit.py |
66 passed, 231 subtests |
tests/const/ + tests/vendor/ + test_dispatch_registry_unit.py |
588 passed, 26811 subtests |
tests/corekit/test_schema_roundtrip_unit.py + tests/project/ |
2137 passed, 80 skipped (pre-existing/unrelated), 0 failed, 11528 subtests |
examples/generators/make_samples.py runs clean (no new failures).
Bugs the full-suite pass caught and fixed (worth flagging explicitly)
- The rebase's auto-merge of the top-level
pcapkit/protocols/data/__init__.pyand.../schema/__init__.py__all__lists resolved without a conflict marker, but left a duplicate'IGMP'entry plus the old single-class design's stale names (IGMP_GroupAddressMessage,IGMP_GroupBody, etc.) that no longer exist — caught bytest_public_api.py's star-import and no-duplicate-entries sweeps, not by anything IGMP-specific. isortwanted different import wrapping in the newigmpv3.pyunder the project's actual-l100 -ppcapkitflags (my first pass used plainisortwith its default shorter line length).- The new
_classifyliteral12(IGMPv3's minimum extended-Query length) coincidentally equalsAH_HEADER_LEN/TCP_DATA_OFFSET_OCTET/GENERIC_BLOCK_MINIMUM; added anUNRELATEDentry totest_rfc_constants_one_home_1739_unit.pyexplaining the coincidence. - One of my own new tests (
test_refusals_name_the_version_refused) used an 8-octet Report fixture to probe IGMPv3's rejection path; a Report type isn't Query-shaped at all, so IGMPv3's schema selector refuses it with "unsupported message type" beforeread()ever runs, not theread()-level "is not an IGMPv3 message" message the test expected. Fixed by using an 8-octet Query fixture instead — the one shape all three versions actually share.
Branch is 4 commits ahead of 57ff1c8c5 relative to its old self, now rebased cleanly onto current origin/main (c6b3848d1).
|
Update on the decision above: since you hadn't weighed in yet and the standing rule here is not to block on an answer, I went ahead with the recommended option (1) -- a concrete |
|
Cross-review (Sonnet) at
|
|
yes option 1, IGMPv3 gets its own class |
|
Confirmed: IGMPv3 gets its own concrete class (Option 1). The architectural choice is approved; ready to merge. |
# Conflicts: # docs/source/contributing/pep.rst # pcapkit/__init__.py # pcapkit/all.py # pcapkit/protocols/__init__.py # pcapkit/protocols/internet/__init__.py # tests/const/test_const_enum_builtin_parity.py # tests/const/test_const_enum_get.py # tests/const/test_const_enum_lookup.py # tests/const/test_const_registry_protocol.py # tests/protocols/test_dispatch_registry_unit.py # tests/vendor/test_vendor_missing_body_unit.py Co-authored-by: JarryShaw <15666417+JarryShaw@users.noreply.github.com>
Please follow the guide below
make pylint,make mypy,make isort)make testpasses, and a test case covers the changeWhat is the purpose of your pull request?
feat— adds a featureDescription of your pull request and other information
Closes #2448. Implements IGMPv1, IGMPv2 and IGMPv3 as one
Internetsubclass (pcapkit.protocols.internet.igmp). Depends on #2444.GroupBodycovers IGMPv1/v2 messages and the IGMPv3 Query; a Query of at least 12 octets adds aQueryExtension(source list). A 9-11 octet Query is refused and falls back toRaw.ReportBodycovers the IGMPv3 Membership Report (0x22), with all six RFC 3376 §4.2.12 record types.0x8cdecodes to 22.4 s.IGMP.lengthis never below the 8-octet fixed header, so a cut header falls back toRawinstead of zero-filled fields.IGMPis wired into theInternetdispatch table and the census tests that enumerate protocols and constants.Testing: unit tests in
tests/protocols/internet/test_igmp_unit.py;coverage run -m pytest tests/protocols/internet/test_igmp_unit.py tests/corekit/test_schema_roundtrip_unit.pypasses.