Skip to main content

CIDR-Bottle

Release Badge Pipeline Badge

CIDR-Bottle is yet another implementation of a Patricia Trie for handling network routing information (such as ROAs & Routing Tables) for reconciliation. However, unlike other implementations it supports both sub-tree checking and longest-prefix matching.

An attractive screenshot of the example code below

CIDR-Bottle was designed specifically to be used for reconciling RIR Allocation & Assignment records with actual BGP Announcements. It isn't designed to be the fastest (it's written in pure python), but it should be the most full-featured implementation. That said, unless you're writing a routing engine in python (in which case I'd be really interested to know why), speed shouldn't be a significant issue.

Dependencies

Usage

Initialisation

By default, a CIDR-Bottle is in IPv4 mode, to use IPv6 mode you must supply an IPv6 CIDR.

The root Bottle does not need to be the entire IP space, it can be any subnet.

from cidr_bottle import Bottle
from ipaddress import IPv4Network, IPv6Network

## Defaults to IPv4
root = Bottle()  # 0.0.0.0/0

## IPv6 mode is initialised by passing an IPv6 CIDR (either as an instance of ipaddress.IPv6Network) 
root6 = Bottle("::/0")  # ::/0

## Supports detached (not starting at either 0.0.0.0/0 or ::/0) roots
detached_root = Bottle("198.51.100.0/24")

Racking a Bottle (Inserting a node)

## Supports insert with str
root.insert("198.51.100.0/24")

## Supports insert with instances of [CIDR-Man's](https://pypi.org/project/cidr-man/) CIDR
root.insert(CIDR("198.51.100.0/24"))

## Supports insert with instances of ipaddress.IPv4Network
root.insert(IPv4Network("198.51.100.0/24"))

## Supports insert with instances of ipaddress.IPv6Network
root.insert(IPv6Network("2001:db8::/48"))

## Supports attaching any json serializable objects to nodes **This is important for future planned releases**
root.insert("198.51.100.0/24", {"example": "dict"})
root.insert("198.51.100.0/24", "string example")

## Supports automatic aggregation on insert.
root.insert(CIDR("192.0.2.128/25"), value="a")
root.insert(CIDR("192.0.2.0/25"), value="b", aggregate=True)
root.insert(CIDR("192.0.3.0/24"), value="c", aggregate=True)
if root.get(CIDR("192.0.2.0/23")).value == "c":  
    ## This will evaluate as True as the two /25's will trigger the creation of the /24 and the addition of the other adjacent /24
    ## will trigger the creation of the /23 

## Supports dict-style indexing
root["198.51.100.0/24"] = "string example"

Note: Setting aggregate=True will (ifnode.parent.left and node.parent.right are populated) insert the node as normal, automatically set the parent object to passing=False, and copy the value from the current insert to the parent.

Contains CIDR?

Returns True where there is a covering prefix, otherwise false. NOTE: This means that it returns true 100% of the time when the root is 0.0.0.0/0 or ::/0

if "198.51.100.0/24" in root:
    ## do something
### or
if root.contains("198.51.100.0/24"):
    ## do something

You can enforce exact matches by passing exact=True to the contains method.

if not root.contains("198.51.100.128/25", exact=True):
    ## do something

Drinking a Bottle (Get node)

This will return a matching covering prefix if present. In the case of a detached root, this means that it can return None if no such covering prefix exists. NOTE: This is longest prefix matching

print(root["198.51.100.0/24"])
### or
print(root.get("198.51.100.0/24"))

Similar to the .contains(...) method, you can enforce exact matches by passing exact=True to the get method. This will raise a KeyError if there is no exact match.

print(root.get("198.51.100.128/25"), exact=True)  # will raise a KeyError("no exact match found")

Children / Sub-Tree checking

With CIDR-Bottle you can retrieve all the defined children of a bottle(node).

root.insert("198.51.100.0/25")
root.insert("198.51.100.128/25")
print(root["198.51.100.0/24"].children())

Smashing bottles (Deleting Nodes)

Deleting an edge node removes it completely.

Deleting an intermediate node, converts it into a "passing" node, and does not affect any descendants of that node.

del root["198.51.100.0/24"]
### or
root.delete("198.51.100.0/24")

More Speed

If you want to squeeze out every last drop of performance and don't mind the limitation of being forced to use CIDR-Man's CIDR then you can use FastBottle instead of Bottle.

Installation (from pip):

pip install cidr_bottle

Installation (from source):

git clone https://gitlab.com/geoip.network/cidr_bottle
poetry install

Metadata

Release files for CIDR-Bottle 1.5.3

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

Source distribution (sdist)

Source distribution for CIDR-Bottle 1.5.3
File Size Uploaded
cidr_bottle-1.5.3.tar.gz 6.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for CIDR-Bottle 1.5.3
File Interpreter ABI Platform
cidr_bottle-1.5.3-py3-none-any.whl Python 3 none any Details

Total release size: 13.4 kB

Release files / cidr_bottle-1.5.3.tar.gz

Download URL cidr_bottle-1.5.3.tar.gz
Size 6.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c854238b497022fe589d42afd856fc9b89e79ea923eb310fd881c0734b4590a2
BLAKE2b-256 checksum
How to use checksums
6381448f2faa0c4dc6f17b37ebd3031f9707559f6ba847b5d4d364541aaa0405
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.13.5 Linux/5.15.154+

Release files / cidr_bottle-1.5.3-py3-none-any.whl

Download URL cidr_bottle-1.5.3-py3-none-any.whl
Size 7.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dba8cc21710146cfdd9c3af8abc05dec0617a7b846257d9da1c8c1fedb500a6a
BLAKE2b-256 checksum
How to use checksums
2cb0a597ad561af322e83b555c3d29b92f22213cede1c97f098047ad5995aeb8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.13.5 Linux/5.15.154+

Release history Release notifications | RSS feed

This release

1.5.3 This release

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

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