-
Notifications
You must be signed in to change notification settings - Fork 1
Basic Concepts
This page explains the fundamental concepts behind dot2net and the topology-driven configuration approach.
Traditional network configuration management faces a critical challenge: tightly coupled topology and configuration. When you need to add a single device to a network, you typically must:
- Configure the new device with appropriate settings
- Update adjacent devices to recognize the new connection
- Calculate and assign IP addresses to avoid conflicts
- Modify routing configurations on related devices
- Ensure consistency across all affected configurations
This process is error-prone, time-consuming, and scales poorly as networks grow larger.
Topology-driven configuration solves this by separating two distinct concerns:
Network Configuration = Topology Description + Generalized Configuration
- Network structure: Which devices exist and how they connect
- Device roles: What type each device is (router, switch, host, etc.)
- Connection properties: Link types, VLANs, protocol layers
- Expressed in: DOT language (Graphviz format)
- Device behavior: How each type of device should be configured
- Template definitions: Reusable configuration patterns
- Parameter policies: Automatic IP assignment, naming schemes
- Expressed in: YAML configuration files
With this separation, you can:
- Change topology by modifying only the DOT file
- Change device behavior by modifying only the YAML templates
- Scale effortlessly as complexity is managed through reusable patterns
- Eliminate errors through automatic parameter calculation and consistency
dot2net automates critical network parameters to eliminate manual errors and ensure consistency across configurations:
- Automatic naming: Consistent object naming using configurable prefix schemes
- Automatic IP assignment: Network-wide IP address calculation and subnet management
- Parameter inheritance: Automatic parameter flow through network hierarchy
These automated features ensure that network configurations remain consistent and error-free as topologies scale and evolve.
dot2net uses a two-level object-oriented paradigm to represent network components:
- Role-independent ownership structure
- Examples: Network, Node, Interface, Connection, Group
- Purpose: Form the hierarchical structure of the network
- Relationship: Top-down ownership model
- Role and behavior definitions
- Examples: "router", "switch", "trunk_port", "access_vlan"
- Purpose: Define how objects should be configured
- Relationship: Bottom-up behavior model
Object = Architecture Class + Configuration Class(es)
- Each object belongs to exactly one AC
- Each object can belong to multiple CCs
- AC defines structure and ownership
- CC defines configuration and behavior
Traditional config templates require complex control syntax (loops, conditionals) because data models lack parameter symmetry. dot2net solves this with:
# Traditional approach (complex)
{% for interface in data.interfaces %}
interface {{ interface.id }}
ip address {{ interface.ip }}/{{ interface.plen }}
{% endfor %}
# dot2net approach (simple)
interface {{ .name }}
ip address {{ .ip_addr }}/{{ .ip_plen }}The key insight: loops are replaced by config block merging. Each Interface object generates its own config block using the same template, and these blocks are automatically merged into the final configuration. No explicit iteration is needed.
The same principle applies when a single object needs to produce multiple similar outputs (e.g., multiple VLANs per switch, multiple static routes per router):
# Traditional approach (nested loops)
{% for vlan in switch.vlans %}
vlan {{ vlan.id }}
name {{ vlan.name }}
{% endfor %}
# dot2net approach (Value class)
vlan {{ .vlan_id }}
name {{ .vlan_name }}With Value class, each VLAN becomes a virtual object (Value) attached to the switch. Each Value generates its own config block, which are then merged - exactly the same pattern as Interface objects, but for dynamically generated parameter sets.
This maintains dot2net's core principle: no control flow syntax in templates, while supporting scenarios that traditionally required loops.
Each object has a symmetric parameter namespace containing:
- Self parameters: Object's own properties
- Relative parameters: Related objects' properties with consistent naming
-
Cross-object references:
{{ .node_name }},{{ .conn_vlan_id }}, etc.
dot2net automatically calculates and assigns:
- IP addresses based on topology and policies
- Interface names following consistent patterns
- Numeric identifiers (VLAN IDs, AS numbers, etc.)
- Cross-references between related objects
Instead of per-device templates, dot2net uses per-object template blocks:
- Node templates: Generate per-device configuration
- Interface templates: Generate per-interface configuration
- Connection templates: Generate per-connection configuration
- Group templates: Generate grouped/aggregated configuration
- Data Model Generation: Build object hierarchy and parameter namespaces
- Template Execution: Process each template block with its object's namespace
- Config Block Generation: Create configuration fragments
- File Assembly: Merge config blocks into final configuration files
dot2net supports multi-layer network descriptions without requiring separate input files:
- Single topology graph with layer-aware labels
- Automatic layer separation during processing
- Examples: IPv4/IPv6 dual-stack, VXLAN overlays, BGP/OSPF multi-protocol
- Simplified input: One DOT file instead of multiple layer-specific files
- Consistent changes: Modify topology once, affects all relevant layers
- Complex protocols: Support overlay networks, tunneling, multi-protocol routing
Objects that correspond directly to topology graph elements:
- Network: The entire network
- Node: Devices (routers, switches, hosts)
- Interface: Device ports/interfaces
- Connection: Links between devices
- Group: Logical groupings (subnets, ASes, clusters)
Objects generated automatically to eliminate control syntax (loops/conditionals):
-
Neighbor: Replaces
for neighbor in interface.neighborsloops -
Member: Replaces
for member in class.membersloops - Segment: Replaces subnet iteration and management
-
Value: Replaces
for item in object.itemsloops - virtual objects that attach multiple parameter sets to a single parent object (e.g., multiple VLANs per switch, multiple static routes per router)
Each referential object generates its own config block using a template, and these blocks are merged automatically - the same pattern that eliminates loops throughout dot2net.
Before (Traditional):
1. Edit router1.conf (add interface, routing)
2. Edit router2.conf (add interface, routing)
3. Edit switch1.conf (add port configuration)
4. Calculate IP addresses manually
5. Update routing tables on 3+ devices
6. Test and debug configuration errors
After (dot2net):
1. Add one line to DOT file: router3 -> switch1
2. Run: dot2net build input.dot
3. Deploy generated configurations
One interface template generates configuration for:
- Hundreds of router interfaces
- Different interface types (trunk, access, loopback)
- Multiple protocols (IPv4, IPv6, MPLS)
- Various network scenarios
The template automatically adapts based on:
- Object's configuration classes
- Calculated parameters (IP, VLAN, etc.)
- Relationships to other objects
- Focus on "what" rather than "how"
- Describe desired state rather than configuration steps
- Let dot2net figure out the implementation details
- Automatic parameter assignment wherever possible
- Manual override capability when needed
- Consistent naming and numbering schemes
- Plugin architecture for new protocols
- Custom modules for specialized requirements
- Standard interfaces for extending functionality
Understanding these concepts enables you to effectively use dot2net for both simple network scenarios and complex, large-scale emulation environments. The topology-driven approach scales from small test networks to enterprise-scale emulations with thousands of devices.