Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

P4 Stateful IPv4 Firewall

This project is a compact stateful IPv4 firewall for P4_16 v1model, BMv2, P4Runtime, and Mininet. IPv4 forwarding, ACL evaluation, TCP state, UDP pseudo-sessions, and expiration all run in the P4 data plane. The Go controller only installs and verifies static configuration.

The TCP tracker is intentionally small and is not a production or RFC-complete connection tracker.

Topology

 h1 (INSIDE) -- port 1 \
                         s1 (P4 firewall) -- port 3 -- h3 (OUTSIDE)
 h2 (INSIDE) -- port 2 /
Host Zone IPv4 address Host MAC Gateway Gateway MAC
h1 INSIDE 10.0.1.1/24 02:00:00:00:01:01 10.0.1.254 02:aa:00:00:01:fe
h2 INSIDE 10.0.2.1/24 02:00:00:00:02:01 10.0.2.254 02:aa:00:00:02:fe
h3 OUTSIDE 10.0.3.1/24 02:00:00:00:03:01 10.0.3.254 02:aa:00:00:03:fe

The switch uses P4Runtime device ID 1, gRPC port 9559, and Thrift port 9090. Hosts use static default routes and permanent gateway neighbors, so the P4 program does not handle ARP. Relevant interface offloads are disabled.

Policy and packet path

The ingress path validates the packet, classifies the ingress port, performs an IPv4 route lookup, evaluates the static ACL, and then applies same-zone or stateful cross-zone policy. A route supplies the egress zone, output port, and Ethernet rewrite, so route validity is established before policy can forward a packet.

The installed ACL rules are evaluated by descending priority:

Priority Rule Decision
300 INSIDE to OUTSIDE, TCP destination port 8081, source 10.0.1.0/24, destination 10.0.3.0/24 Drop
200 INSIDE to OUTSIDE, UDP destination port 9000 Allow
100 INSIDE to OUTSIDE, TCP Allow

The ACL table can match ingress and egress zones, IPv4 source and destination, protocol, and source and destination transport ports. An explicit drop is terminal and takes precedence over lower-priority allow rules. An ACL allow is required to create new INSIDE-to-OUTSIDE state. An ACL miss cannot create state, although matching existing state may pass.

The default behavior is:

  • valid INSIDE-to-INSIDE TCP or UDP is allowed unless explicitly denied;
  • ACL-allowed INSIDE-to-OUTSIDE TCP or UDP may create state;
  • matching OUTSIDE-to-INSIDE return traffic may use existing state;
  • unsolicited OUTSIDE-to-INSIDE TCP or UDP is dropped;
  • route misses, unknown ingress ports, and all other traffic are dropped.

Accepted packets preserve IPv4 and transport addresses, rewrite both Ethernet addresses, decrement TTL exactly once, and recompute the IPv4 header checksum.

Stateful flow table

Both directions use this canonical key:

internal IPv4, external IPv4, internal port, external port, IP protocol

CRC32 maps the key into one of 1,024 direct-mapped slots. Parallel registers store the full canonical key, state, and a 48-bit last-seen timestamp. Every stored key field must match before state can authorize a packet. A different flow that collides at the same index is dropped and cannot overwrite or refresh the resident entry.

Expiration is lazy. It is evaluated when the resident key next accesses its slot; there is no controller scan. Consequently, a different colliding key cannot reclaim an expired resident entry until the resident key accesses or clears that slot. This fixed-size design deliberately trades availability for fail-closed collision behavior.

The timestamp is BMv2's 48-bit ingress timestamp in microseconds. Unsigned age subtraction assumes an entry is not left untouched across a full timestamp period, approximately 8.9 years.

TCP

NONE -- allowed INSIDE SYN --> SYN_SENT
SYN_SENT -- matching OUTSIDE SYN+ACK --> SYN_REPLIED
SYN_REPLIED -- matching INSIDE ACK --> ESTABLISHED

Initial SYN and SYN+ACK packets use exact simplified flag combinations. In ESTABLISHED, a matching packet must have ACK set and SYN, FIN, and RST clear. Other transitions fail closed.

An exact RST or RST+ACK in tracked state is forwarded and immediately clears the slot. A bare FIN is dropped without clearing state. The tested inside-originating FIN+ACK in ESTABLISHED is forwarded and immediately clears state; a later peer ACK is therefore dropped. No bidirectional TCP closing state is implemented.

Handshake state expires after 2 seconds. Established state expires after 3 seconds. Matching traffic that retains handshake or established state refreshes the applicable timer.

UDP

An ACL-allowed INSIDE-to-OUTSIDE datagram creates an active pseudo-session. Matching datagrams in either direction refresh it. Unsolicited return traffic and wrong address or port tuples are dropped. UDP state expires after 2 seconds.

Packet validation

Only Ethernet carrying IPv4 with TCP or UDP is supported. The firewall drops:

  • non-IPv4 Ethernet and unsupported IPv4 protocols;
  • IPv4 versions other than 4 and IPv4 options (IHL != 5);
  • bad IPv4 header checksums, total lengths below 20 bytes, or total lengths larger than the received IPv4 packet;
  • MF or a nonzero fragment offset;
  • TTL values of 1 or less;
  • TCP data offsets below five words or nonzero TCP reserved bits;
  • UDP lengths below eight bytes or inconsistent with the IPv4 payload length;
  • route misses, ACL denial, invalid state transitions, flow-key collisions, and unsolicited return traffic with missing or expired state.

TCP and UDP checksums are not validated. TCP sequence numbers, acknowledgment numbers, and options are not interpreted.

Control plane

The controller uses p4runtime-go-controller and is a one-shot configurator. It becomes primary, installs the P4Info and BMv2 device configuration, inserts three zone entries, three routes, and three ACL entries, reads the pipeline and table entries back, and exits. It does not receive normal packets or maintain flow state.

Against a running configured switch, readback can be repeated without writing the pipeline or tables:

build/firewall-controller -verify-only

Verification still participates briefly in P4Runtime primary arbitration. A normal install uses insert operations and is intended for a fresh --no-p4 switch rather than as an idempotent reconciliation command.

Prerequisites

  • Linux with root privileges for Mininet and BMv2 interfaces;
  • p4c-bm2-ss with P4_16 and v1model support;
  • simple_switch_grpc;
  • Mininet, Python 3, and Scapy;
  • Go 1.25.3 or a compatible newer toolchain;
  • ip and ethtool.

The Go module pins the P4Runtime controller and protocol dependencies. No separate P4 toolchain installation is performed by this project.

Build, run, and test

make build

Build output is written under ignored build/. To start the topology, install and verify the pipeline, and enter the Mininet CLI:

make run

The runtime requires ports 9559 and 9090 and the deterministic interface names to be free. Enter exit in the Mininet CLI to stop the owned switch, hosts, links, and temporary runtime directory.

Run all build, controller, artifact, and packet-level integration tests with:

make test

make test-unit does not create Mininet links. make test-integration runs the privileged live topology suite. The packet tests exercise real TCP and UDP sockets plus crafted traffic for ACL boundaries, TCP transitions, UDP expiry, deterministic CRC32 collisions, fragments, malformed headers, route misses, TTL, checksum recomputation, MAC rewriting, and duplicate forwarding. Captures remain in memory; BMv2 logs, sockets, and other runtime files use temporary directories and are removed during cleanup.

Remove project-generated build output and Python bytecode with:

make clean

Limitations

  • This is a reference firewall, not a production TCP connection tracker.
  • IPv4 fragmentation and IPv4 options are unsupported and dropped.
  • IPv6, ARP, ICMP, and protocols other than TCP and UDP are unsupported.
  • The flow table has 1,024 direct-mapped slots and no collision chaining.
  • TCP closing, sequence validation, normalization, and transport-checksum validation are intentionally out of scope.
  • NAT, routing protocols, DPI, VPN functions, and controller-managed conntrack are not implemented.

About

A stateful IPv4 firewall in P4_16 with zone-based policy, ACLs, TCP/UDP flow tracking, P4Runtime configuration, Mininet topology, and packet-level integration tests.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages