Skip to main content

PyTCP

Pure-Python, zero-dependency TCP/IP stack — Ethernet through RFC 9293 TCP — running in user space on a TAP/TUN interface, embeddable in-process or run as a daemon, with a Berkeley-sockets API.

from pmd_pytcp import socket, stack

What it is

A full, RFC-grounded TCP/IP stack implemented entirely in Python: Ethernet II / 802.3 (LLC/SNAP), ARP, IPv4 / IPv6 (with Hop-by-Hop / Destination-Options / Routing / Fragment extension headers), ICMPv4 / ICMPv6 (incl. Neighbor Discovery, MLDv2 with MLDv1 fallback, and IGMP IPv4 multicast group membership), DHCPv4 and DHCPv6 clients, UDP, and a RFC 9293 TCP with a real FSM, congestion control (Reno / NewReno / CUBIC), SACK / timestamps / window-scaling, and a BSD-sockets facade. It runs on a TAP/TUN interface in user space — no kernel module, no privileged data path. It can be embedded in-process as a library, or run as a daemon that out-of-process clients drive over an AF_UNIX control boundary — the kernel/userspace split described below.

The project's north star is feature-equivalence with the Linux host network stack: where an RFC is unambiguous PyTCP follows it, and where it is silent or offers a menu PyTCP picks the Linux choice. Per-RFC adherence is audited under docs/rfc/.

The three distributions

PyTCP is strictly layered into three independently-published dists (one invariant: project folder == import name):

Distribution Import Role
PyTCP-pmd_net_addr pmd_net_addr Address value types (IPv4/IPv6/MAC, networks, masks, wildcards, interface-addresses).
PyTCP-pmd_net_proto pmd_net_proto Protocol packet parse / assemble / validate.
PyTCP pmd_pytcp The running stack: subsystems/threads, sockets, FIB, ARP/ND caches, RX/TX rings.

Installing PyTCP pulls the other two automatically (lockstep version pin).

Runtime architecture

TAP/TUN fd ─> RxRing ─> PacketHandler (per protocol, RX) ─> Socket queues / ARP+ND caches / fragment store
           <─ TxRing <─ PacketHandler (per protocol, TX) <─ Socket send / ND / DHCP / ACD
  • Subsystem base — every background service (RX/TX rings, neighbor caches, timer, DHCPv4 / DHCPv6 clients, link-local / ACD) extends Subsystem and runs its own thread with an event-driven loop.
  • Packet handlers — RX and TX paths are composed from per-protocol sub-handlers (packet_handler__<proto>__<rx|tx>.py). Every branch bumps a per-protocol stat counter for observability.
  • Event-driven timer — a heap-based deadline scheduler (no polling tick); subsystems register deadlines and are woken on the nearest one.
  • Per-interface model — a PacketHandler is an interface. A multi-homed host runs one handler per interface; global tables (routing FIB, socket table, neighbor caches) are shared and lock-guarded.

Free-threaded (no-GIL) safety

Per-interface state is partitioned (single-writer TX ring hand-off); the shared global tables (RouteTable, SocketTable, InterfaceTable) guard their compound (check-then-act) operations with a small threading.Lock and hand readers consistent snapshots. Single built-in dict/list ops are left lock-free (individually atomic).

Control-plane APIs (the Phase-3 kernel/userspace boundary)

Consumers talk to the stack only through sanctioned surfaces — never by reaching into runtime internals — mirroring how a Linux process talks to its kernel:

API Linux equivalent
pmd_pytcp.socket — BSD socket() factory + methods (TCP / UDP / raw / AF_PACKET) socket(2)
pmd_pytcp.stack.sysctl — runtime-tunable policy registry /proc/sys/net/
pmd_pytcp.stack.link — per-interface MAC / MTU / state / counters ip link / RTM_*LINK
pmd_pytcp.stack.address — assign / remove IPv4 / IPv6 host addresses ip addr / RTM_*ADDR
pmd_pytcp.stack.route — add / remove / list routes (FIB); Route / RouteProtocol / RouteScope ip route / RTM_*ROUTE
pmd_pytcp.stack.neighbor — static ARP / ND entries, cache flush ip neighbor / RTM_*NEIGH
read-only snapshots (route table, neighbor cache, socket list, counters) /proc/net/*, ss

Lifecycle

stack.init(...) builds the singletons, stack.add_interface(...) / stack.remove_interface(...) attach / detach interfaces at runtime (RTNETLINK RTM_NEWLINK / RTM_DELLINK semantics, including the address / route / neighbor / session teardown cascade), stack.start() spawns the subsystem threads, and stack.stop() winds them down. A stack can init() with zero interfaces and gain them later — the daemon / multi-homed shape.

Sockets

pmd_pytcp.socket mirrors the stdlib socket module: a socket(...) factory returns TcpSocket / UdpSocket / RawSocket / PacketSocket, with bind / listen / accept / connect / send / recv / close, fileno() + eventfd for selectors integration, blocking & non-blocking modes, errno-mapped OSError, getaddrinfo, common setsockopt options, IPv4/IPv6 multicast group membership and source-filter options (IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IPV6_JOIN_GROUP, …), and an IP_RECVERR / MSG_ERRQUEUE error queue. Stdlib-parity constants (AF_INET, SOCK_STREAM, IP_*, SO_*, MSG_*) are exposed as bare module names backed by IntEnums.

Daemon mode — out-of-process clients

The stack runs as a daemon: a normal in-process stack that also listens on an AF_UNIX control socket, so a separate process opens sockets and drives the control-plane APIs through pmd_pytcp.client — exactly the way a Linux process talks to the kernel. The client never boots the stack; it holds real, selectors-pollable socket fds handed to it across the boundary via SCM_RIGHTS.

Start the daemon (it owns the TAP interface); the first-class entry point ships in the package as python -m pmd_pytcp.daemon (or the pytcpd console script after install), defaulting the control socket to $XDG_RUNTIME_DIR/pmd_pytcp.sock:

python -m pmd_pytcp.daemon --ipc-socket /tmp/pmd_pytcp.sock

Then, from any other process — note it imports pmd_pytcp.client, boots no stack, and calls no stack.init():

from pmd_pytcp.client import connect
from pmd_pytcp.socket import AddressFamily, SocketType

with connect(socket_path="/tmp/pmd_pytcp.sock") as client:
    sock = client.socket(AddressFamily.INET4, SocketType.STREAM)
    sock.connect(("10.0.1.1", 7))   # a real, selectable fd backs this socket
    sock.send(b"hello")
    print(sock.recv(5))

The same client.socket(...) factory returns UDP / raw / AF_PACKET sockets, and client.sysctl / .route / .link / .address / .neighbor / .membership mirror the in-process control APIs across the boundary. See examples/client__tcp_echo_ipc.py.

Install

pip install PyTCP

Brings in PyTCP-pmd_net_proto and PyTCP-pmd_net_addr — no other runtime dependencies (the whole stack is stdlib-only). Fully typed (ships py.typed, PEP 561); strict-mypy clean.

Running the stack

Running needs one or more TAP/TUN interfaces (root for interface / bridge setup). Bridged TAP interfaces (Ethernet) are created on the br0 bridge, so the bridge comes first:

make bridge      # create the br0 bridge (sudo)
make tap7        # create tap7, add it to br0 (sudo)
make tap9        # create a second tap, tap9, on br0 (sudo)
make run         # run the stack on tap7
make run_multi   # multi-interface demo (runs on tap7 + tap9)

Point-to-point TUN interfaces (IP), each created pre-addressed and needing no bridge, are also available — make tun3 (172.16.1.1/24, 2001:db8:1::1/64) and make tun5 (172.16.2.1/24, 2001:db8:2::1/64) set up the host side, and make run_tun / make run_tun5 run the stack on the matching device (taking the .2 host in each subnet). A stack can init() with zero interfaces and add / remove them at runtime, so any mix of taps and tuns can be attached to one running stack.

PyTCP is consumed as a library through the stack lifecycle API and the pmd_pytcp.socket BSD-sockets API. See examples/ — examples/stack.py is the complete runnable reference (TAP/TUN open, stack.init(...), multi-interface bind, runtime interface removal on SIGUSR1).

Requirements

Python 3.14+, Linux (TAP/TUN), POSIX.

Current state (3.0.7)

  • ~210 source modules; 3.0.7 adds the kernel/userspace IPC layer (an ipc AF_UNIX RPC + SCM_RIGHTS fd-passing core, a client out-of-process mirror, and a first-class daemon entry point). The pmd_pytcp suite runs ~4,000 unit + integration tests (the full repo suite, across all three packages + examples, is ~12,500). Lint clean (codespell + isort + black + flake8 + mypy strict + pylint).
  • Host-stack feature-complete (North Star Phase 1), now reachable both in-process and over an out-of-process daemon boundary (AF_UNIX control plane + SCM_RIGHTS socket-fd passing for TCP / UDP / raw / AF_PACKET). Phase-2 router/forwarding sits behind the forward_or_deliver seam as a stub. Authoring contracts in .claude/rules/pmd_pytcp.md; per-RFC adherence in docs/rfc/.

License

GPL-3.0-or-later. PyTCP by Sebastian Majewski.

Metadata

Release files for pmd-pytcp 0.3.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pmd-pytcp 0.3.8
File Size Uploaded Provenance Actions
pmd_pytcp-0.3.8.tar.gz 578.9 kB With provenance Details for pmd_pytcp-0.3.8.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pmd-pytcp 0.3.8
File Interpreter ABI Platform Actions
pmd_pytcp-0.3.8-py3-none-any.whl Python 3 none any Details for pmd_pytcp-0.3.8-py3-none-any.whl

Total release size: 1.4 MB

Release files / pmd_pytcp-0.3.8.tar.gz

Download URL pmd_pytcp-0.3.8.tar.gz
Size 578.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a26e76e735a04bb6bbcec0793aadcd4f20f03778fd29971a3e2747ce394e9795
BLAKE2b-256 checksum
How to use checksums
f874e9a79796df33932558913d309fba9015080c4e241cdb61e6280421db4be7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / pmd_pytcp-0.3.8-py3-none-any.whl

Download URL pmd_pytcp-0.3.8-py3-none-any.whl
Size 780.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f41cc0a22f83eb3e885d2d4228d094ad5a98e787678a18af1dacf15f77489e04
BLAKE2b-256 checksum
How to use checksums
432ddc4c738d58e9143f74d53bca753d49b48db438b35f1ff8ca974d6efd2d2b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Security for pmd-pytcp 0.3.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pmd_pytcp-0.3.8.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page