Script Open Virtual Network (OVN) directly
from Python. Instead of describing infrastructure in a declarative
configuration and relying on a reconciler, use ovn to create and manage
network resources with a Django-style ORM for the OVN Northbound database.
ovn ships a pure OVSDB client
that connects to the Northbound database over JSON-RPC. It has no runtime
dependency on the ovn or ovs C command-line tools.
Install
pip install ovn
Quick example
from ovn.models import LogicalRouter, LogicalSwitch
# create a network object
switch = LogicalSwitch(name="sw0")
# save it to the OVN database (yes, OVN works like that)
switch.save()
# another object
router = LogicalRouter(name="ro0")
router.save()
# connect them!
switch.plug(router,
mac="00:11:22:33:44:55",
networks="192.168.100.1/24")
Each OVN Northbound table maps to a model class, and every class exposes a
Django-style .objects manager:
from ovn.models import LogicalSwitch
LogicalSwitch.objects.create(name="sw1") # insert
LogicalSwitch.objects.list() # SELECT *
sw = LogicalSwitch.objects.get_by_name("sw1")
sw.delete()
An instance is just a row. Set attributes and call save() to sync; call
fetch() (or refresh_from_db()) to reload from the database.
High-level network shortcuts
The ovn.shortcuts module composes models for common workflows while leaving
the regular model API available. For example, create a tenant router and routed
segment, then attach a DHCP-addressed workload:
from ovn.shortcuts import attach_workload, create_tenant_network
tenant = create_tenant_network(
name="app",
subnet="10.0.1.0/24",
gateway="10.0.1.1",
router_port_mac="00:11:22:33:44:55",
dhcp_options={
"server_id": "10.0.1.1",
"server_mac": "00:11:22:33:44:55",
"lease_time": "3600",
},
)
assert tenant.segment.dhcp_options is not None
workload_port = attach_workload(
tenant.segment.switch,
name="app-vm1",
mac="00:11:22:33:44:66",
dhcp_options=tenant.segment.dhcp_options,
)
| Helper | Description |
|---|---|
create_network_segment(...) |
Creates a logical switch and connects it to an existing router. Can also create DHCP options for the subnet. |
create_tenant_network(...) |
Creates a router and one routed segment. |
attach_workload(...) |
Attaches a switch port with either a static ip_address or dhcp_options; provide exactly one. |
configure_outbound_nat(...) |
Creates and attaches a source-NAT rule to a router. Does not create an external network, router interface, or default route. |
configure_static_route(...) |
Adds a static route to a router after validating destination and next-hop IP versions. |
apply_security_policy(...) |
Attaches caller-defined ACLRule rules to a port group. |
allow_web_traffic(...) |
A preset security policy for TCP ports 80 and 443. |
create_service_endpoint(...) |
Creates a load balancer and attaches it to selected switches and/or routers. VIP and backends use OVN's IP:port format. |
Helpers return the created model instances (or workflow dataclasses) for further customization. Multi-step workflows perform several database operations and are not atomic; a failure can leave earlier rows in place.
Configuration
The server address is read from the OVN_NB_DB environment variable (default
unix:/run/ovn/ovnnb_db.sock). Two formats are accepted:
export OVN_NB_DB=unix:/run/ovn/ovnnb_db.sock # local socket
export OVN_NB_DB=tcp:127.0.0.1:6641 # remote / TCP
Importing
ovn.modelsnever touches the database. The schema is fetched (and cached) lazily on first real use, so imports,--help, and test collection all work without a reachable DB.
CLI
The package installs an ovn console script:
ovn shell # IPython shell with every model preloaded
ovn schema # dump the live Northbound schema as JSON
MCP server (optional)
Install the MCP extra and start the stdio server:
pip install "ovn[mcp]"
ovn-mcp
The server exposes basic tools for listing, looking up, creating, and deleting
logical switches and routers, plus listing, creating, and deleting their
attached ports. Tool results include the loaded model row fields. It uses the
configured OVN_NB_DB endpoint and connects only when a tool is called.
Docker network driver (optional)
With the docker extra installed (pip install "ovn[docker]"), ovn can act
as a libnetwork remote driver,
backing Docker networks with OVN logical switches on a single host:
ovn-docker-driver
# then, on the same host:
docker network create -d ovn mynet
The CreateNetwork API methods translates into a Logical_Switch, each container gets a
Logical_Switch_Port bound to the local integration bridge (br-int). See
ovn/docker.py for the full mapping.
Architecture
It helps to understand the overall architecture of OVN first — see the official documentation, summed up below.
ovn is a thin OVN Northbound client. It manages the database; OVN does the
rest.
Internally it is layered low → high:
| Layer | Module | Role |
|---|---|---|
| Wire protocol | ovn/ovsdb/ |
raw OVSDB JSON-RPC (transport, ovsdb_client) |
| Schema | ovn/schema.py |
pydantic models of the OVSDB schema + (de)serialization |
| Client | ovn/client.py |
OVNClient + transaction composer for OVN_Northbound |
| Manager | ovn/manager.py |
Manager[T]: the .objects query/CRUD interface |
| Models | ovn/models/ |
one thin class per Northbound table |
Development
The project uses uv and targets Python ≥ 3.12.
uv sync
uv run pytest # transport tests need no DB; model/client tests need one
A local OVN Northbound DB is needed for anything touching models or the client. Spin one up with the bundled compose file:
cd docker && docker compose up --build # NB DB on 127.0.0.1:6641
export OVN_NB_DB=tcp:127.0.0.1:6641
License
Licensed under the Apache License, Version 2.0.
Metadata
Release files for ovn 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ovn-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / ovn-0.1.0-py3-none-any.whl
| Download URL | ovn-0.1.0-py3-none-any.whl |
|---|---|
| Size | 48.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5ee66b8e84879376449f17d0078fcc25055a9962b1e14802ae5fc2454fbae5a7
|
|
BLAKE2b-256 checksum How to use checksums |
f2f047f175a417eefc1e4dcad8f860932aa8d570a9bad881b3548d34a82214e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 24, 2026.
Transparency logSecurity for ovn 0.1.0
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
All 1 file in this release has been uploaded with provenance metadata.
Attestation for ovn-0.1.0-py3-none-any.whl
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 24, 2026.
Transparency logA 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.