bgpframe
English documentation.
Korean version: docs/README.ko.md
A Rust-based MRT (BGP) parsing + Parquet processing library.
You can build and use it directly from Python with maturin, and write concise prefix containment queries with Polars expressions.
Key Highlights
- Fast parsing: converts MRT to Parquet using
bgpkit-parser+ Rust implementation. - Memory reuse: reduces allocation/copy overhead with batch buffer swap during flush.
- Rust scan filter:
parquet_filter_updatesfor fast direct filtering/writing on large Parquet files. - Python-friendly API: prefix/IP containment + BGP-specific filters (
announce,origin,as_path). - Typed API: includes
.pyistubs (_core.pyi,polars_utils.pyi,__init__.pyi).
Installation
Install from PyPI:
pip install bgpframe
If you use the Polars helper expressions:
pip install "bgpframe[polars]"
Using uv:
uv add bgpframe
# or
uv add "bgpframe[polars]"
Requirements
- Rust stable toolchain
- Python 3.12+
uvmaturin
Development Build
uv venv
source .venv/bin/activate
uv pip install maturin
maturin develop
python -c "import bgpframe; print(bgpframe.hello())"
Run without activating the virtual environment:
uv run -- maturin develop
uv run python -c "import bgpframe; print(bgpframe.hello())"
Examples
1) MRT -> Parquet
import bgpframe
bgpframe.mrt_to_parquet(
"https://data.ris.ripe.net/rrc00/latest-update.gz",
"rrc00_latest.parquet",
limit=200_000, # optional
batch_size=100_000, # optional
)
2) Prefix containment query (IPv4/IPv6)
import bgpframe
import polars as pl
df = pl.read_parquet("rrc00_latest.parquet")
res = df.filter(bgpframe.contains_prefix_expr("8.8.8.8"))
print(res.head())
3) Filter large Parquet and write output
import bgpframe
matched = bgpframe.parquet_contains_ip(
"rrc00_latest.parquet",
"2001:4860:4860::8888",
output="rrc00_latest_match_google_dns_v6.parquet",
limit=100_000, # optional
)
print("matched rows:", matched)
4) Combined BGP convenience filters
import bgpframe
import polars as pl
df = pl.read_parquet("rrc00_latest.parquet")
# announce + origin AS 15169 + AS_PATH includes 3356 + path length 2..5
res = bgpframe.filter_bgp_updates(
df,
elem_type="announce",
origin_asn=15169,
as_path_contains=3356,
min_as_path_len=2,
max_as_path_len=5,
)
# exact prefix match (host bits are normalized with strict=False behavior)
exact = df.filter(bgpframe.prefix_exact_expr("2001:4860:4860::8888/32"))
5) Rust high-speed scan filter (file -> file)
import bgpframe
matched = bgpframe.parquet_filter_updates(
"rrc00_latest.parquet",
output="rrc00_latest_updates_filtered.parquet",
contains_ip="8.8.8.8",
elem_type="announce",
origin_asn=15169,
as_path_contains=3356,
min_as_path_len=2,
max_as_path_len=8,
limit=50_000,
)
print("matched rows:", matched)
The same code is available at example/parquet_filter_updates.py.
Recommended Query Patterns for BGP Data
- Split event types:
announce_expr(),withdraw_expr() - Analyze route origin:
origin_asn_expr(asn) - Track transit/upstream ASN:
as_path_contains_expr(asn) - Find policy/risk signals:
as_path_len_between_expr(min_len=..., max_len=...) - Exact prefix comparisons:
prefix_exact_expr("x.x.x.x/len") - Apply combined filters once:
filter_bgp_updates(...) - Direct Parquet processing:
parquet_filter_updates(...)
Testing / Quality Gates
Results below are from local runs on 2026-03-01 (Asia/Seoul).
- Rust unit tests:
7 passed - Rust doc tests:
0 failed - Python regression tests (
unittest):6 passed - Python doctest:
4 passed - Coverage (Python):
93% - Type check (
pyrefly):0 errors
Run commands:
# One-time workaround if cargo test has macOS + Homebrew Python framework link issue
mkdir -p /tmp/Python3.framework/Versions/3.9
ln -sf /opt/homebrew/Frameworks/Python.framework/Versions/Current/Python /tmp/Python3.framework/Versions/3.9/Python3
# Rust tests
DYLD_FRAMEWORK_PATH=/tmp cargo test --lib
DYLD_FRAMEWORK_PATH=/tmp cargo test --doc
# Python tests + doctest
uv run python -m unittest -v tests.test_regression
uv run python -m doctest -v src/bgpframe/polars_utils.py
# Coverage
uv run coverage erase
uv run coverage run -m unittest tests.test_regression
uv run coverage run -a -m doctest src/bgpframe/polars_utils.py
uv run coverage report
# Type check
uv run pyrefly check
CI/CD and PyPI Publishing
- CI workflow:
.github/workflows/ci.yml- Trigger: push to
main, pull requests - Runs: Rust tests, Python regression tests, doctest, type checks
- Trigger: push to
- Automated release workflow:
.github/workflows/release-please.yml- Trigger: push to
main(or manual dispatch) - Creates/updates a Release PR, updates versions (
pyproject.toml,Cargo.toml), and publishes a GitHub Release
- Trigger: push to
- Release workflow:
.github/workflows/publish-pypi.yml- Trigger: GitHub Release (
published/released) or manual dispatch - Builds: wheels (
ubuntu/macos/windows) + sdist - Publishes: PyPI via Trusted Publishing (OIDC)
- Trigger: GitHub Release (
Required setup for PyPI release
- Configure a PyPI Trusted Publisher for this project.
- In PyPI Trusted Publisher settings, use:
- Owner:
taeyun16 - Repository:
bgpframe - Workflow filename:
publish-pypi.yml - Environment name:
pypi
- Owner:
- In GitHub, create environment
pypi(Settings -> Environments). - Create a GitHub Release (for example tag
v0.1.0) to trigger publish.
With Trusted Publishing, you do not need a long-lived PYPI_API_TOKEN secret.
Automatic release flow
- Merge commits into
main(use Conventional Commit prefixes likefeat:,fix:,docs:). release-pleaseopens/updates a Release PR with version/changelog changes.- Merge the Release PR.
release-pleasecreates a GitHub Release.publish-pypi.ymlruns and uploads artifacts to PyPI.
Schema Summary
The schema is normalized to numeric/list columns and minimizes string fields.
| Column | Type | Description |
|---|---|---|
timestamp |
i64 | Unix timestamp in seconds |
elem_type |
u32 | announce=1, withdraw=0 |
peer_ip_ver |
u32 | 4 or 6 |
peer_ip_v4 |
u32? | Present only for IPv4 peers |
peer_ip_v6_hi |
u64? | Upper 64 bits of IPv6 |
peer_ip_v6_lo |
u64? | Lower 64 bits of IPv6 |
peer_asn |
u32 | Peer ASN |
prefix_ver |
u32 | 4 or 6 |
prefix_v4 |
u32? | IPv4 prefix |
prefix_v6_hi |
u64? | Upper 64 bits of IPv6 |
prefix_v6_lo |
u64? | Lower 64 bits of IPv6 |
prefix_len |
u32 | Prefix length |
prefix_end_v4 |
u32? | IPv4 range end (query acceleration) |
next_hop_ver |
u32? | 4 or 6 |
next_hop_v4 |
u32? | IPv4 next hop |
next_hop_v6_hi |
u64? | Upper 64 bits of IPv6 |
next_hop_v6_lo |
u64? | Lower 64 bits of IPv6 |
as_path |
list | Flattened AS_PATH |
as_path_len |
u32 | Route length |
has_as_set |
bool | Contains AS_SET/CONFED_SET |
origin_asn |
u32? | Present only for a single origin ASN |
local_pref |
u32? | local-pref |
med |
u32? | MED |
Metadata
Release files for bgpframe 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bgpframe-0.2.0.tar.gz | 60.9 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bgpframe-0.2.0-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| bgpframe-0.2.0-cp39-abi3-manylinux_2_38_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.38+ x86-64 | Details |
| bgpframe-0.2.0-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 28.2 MB
Release files / bgpframe-0.2.0.tar.gz
| Download URL | bgpframe-0.2.0.tar.gz |
|---|---|
| Size | 60.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1a52a883eb2c6dffa41d5ff85fb1acf4f55d3f381df49143dd4509253272586
|
|
BLAKE2b-256 checksum How to use checksums |
891078cc5875beedce3c029516021878aee9e34b1aa88d6a122b2e7965e7eeeb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 28, 2026.
Transparency logRelease files / bgpframe-0.2.0-cp39-abi3-win_amd64.whl
| Download URL | bgpframe-0.2.0-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 8.8 MB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
fb8223fc59869940dbe12c5c6c43bf7ea1b1e369a090eef21468f1d3dc751827
|
|
BLAKE2b-256 checksum How to use checksums |
0c8c633cef3a4aba9e136e2c3573e60458079933c2918276a399679c3b021d6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 28, 2026.
Transparency logRelease files / bgpframe-0.2.0-cp39-abi3-manylinux_2_38_x86_64.whl
| Download URL | bgpframe-0.2.0-cp39-abi3-manylinux_2_38_x86_64.whl |
|---|---|
| Size | 10.3 MB |
| Tags | CPython 3.9 Linux glibc 2.38+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
295383ef22362ae06f7c16edff00f4fcbeb14ee19e9e71ab3fb74b059ab9b517
|
|
BLAKE2b-256 checksum How to use checksums |
c001246a9befb4723093fd3c42245705ab4ac6e13c1c5f0d1dca4c15785637c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 28, 2026.
Transparency logRelease files / bgpframe-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | bgpframe-0.2.0-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 9.1 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
5e4038ee4cf7cb7278dd8668cffa23b98936e2ed7b32216fc8fb0c10e2a9a405
|
|
BLAKE2b-256 checksum How to use checksums |
2b8d36dcf7c4c1256e4b1c6f5a885e96dc64d85b048eda8a422aa5fe37b356e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Feb 28, 2026.
Transparency log