Target: 2.5.0 (Tier 3 — L2 discovery & tunneling)
Context
MPLS is registry.py's own canonical "how to add a protocol"
example (@register("ethertype", 0x8847) class MPLS(Protocol): ...),
repeated in ARCHITECTURE.md, README.md, and docs/CLAIMS.md as
the illustration of extending the library without editing its
source — and it's real code nobody has actually written yet.
Deliverable
Add netprotocols.MPLS (layer 2, dispatched from ethertype):
- Decode the 4-byte label stack entry (RFC 3032 §2.1): Label (20
bits), Traffic Class/EXP (3 bits), Bottom of Stack "S" bit (1 bit),
TTL (8 bits). MPLS frames carry a stack of these — decode
entries until S=1 marks the bottom, exposing MPLS.labels as a
tuple rather than modeling only a single label.
- Design question, not a footnote: MPLS's shim header has no
next-protocol field. There is no way to know from the header alone
whether the payload below the bottom label is IPv4, IPv6, or
something else. Real stacks resolve this by convention, not
signaling: sniff the payload's first nibble (4 → IPv4, 6 → IPv6) —
the same heuristic dpkt and scapy both use, since RFC 4928's
Pseudowire Control Word (a leading zero nibble) is the only other
common case and is itself distinguishable from 4/6. Implement
next_protocol() as that sniff, and say so plainly in the
docstring — this is the one place in the library where dispatch
isn't a clean table lookup on a wire value.
- Add
EtherType.MPLS — RFC 3032 defines two: unicast (0x8847) and
multicast (0x8848) — with display names; wire both into Ethernet
dispatch to the same MPLS class.
Acceptance criteria
References
RFC 3032 · Canonical extension example: registry.py,
ARCHITECTURE.md, README.md, docs/CLAIMS.md
Part of #173
Target: 2.5.0 (Tier 3 — L2 discovery & tunneling)
Context
MPLS is
registry.py's own canonical "how to add a protocol"example (
@register("ethertype", 0x8847) class MPLS(Protocol): ...),repeated in
ARCHITECTURE.md,README.md, anddocs/CLAIMS.mdasthe illustration of extending the library without editing its
source — and it's real code nobody has actually written yet.
Deliverable
Add
netprotocols.MPLS(layer 2, dispatched fromethertype):bits), Traffic Class/EXP (3 bits), Bottom of Stack "S" bit (1 bit),
TTL (8 bits). MPLS frames carry a stack of these — decode
entries until
S=1marks the bottom, exposingMPLS.labelsas atuple rather than modeling only a single label.
next-protocol field. There is no way to know from the header alone
whether the payload below the bottom label is IPv4, IPv6, or
something else. Real stacks resolve this by convention, not
signaling: sniff the payload's first nibble (4 → IPv4, 6 → IPv6) —
the same heuristic dpkt and scapy both use, since RFC 4928's
Pseudowire Control Word (a leading zero nibble) is the only other
common case and is itself distinguishable from 4/6. Implement
next_protocol()as that sniff, and say so plainly in thedocstring — this is the one place in the library where dispatch
isn't a clean table lookup on a wire value.
EtherType.MPLS— RFC 3032 defines two: unicast (0x8847) andmulticast (0x8848) — with display names; wire both into Ethernet
dispatch to the same
MPLSclass.Acceptance criteria
MPLSdecodes a full label stack (single and multi-labelcases);
bytes(MPLS.decode(x)) == x.next_protocol()implements the first-nibble heuristic,documented as such, correctly resolving IPv4/IPv6-carrying MPLS
frames end to end.
MPLS.References
RFC 3032 · Canonical extension example:
registry.py,ARCHITECTURE.md,README.md,docs/CLAIMS.mdPart of #173