-
Notifications
You must be signed in to change notification settings - Fork 1
YAML Configuration
This page explains the YAML configuration system in dot2net, including class definitions, template syntax, and configuration patterns.
YAML configuration files define the generalized configuration part of topology-driven configuration. While DOT files describe "what" the network topology is, YAML files describe "how" each type of device should be configured.
Global settings control project-wide behavior:
global:
path: local # "local" = files in config dir, "default" = working dir
mountsourcepath: local # "local" or "abs" for mount paths
nodeautoname: true # Enable automatic node renamingKey attributes:
-
path: File path specification for config files referenced in YAML-
"local": Paths relative to input.yaml directory -
"default": Paths relative to current working directory (shell execution location)
-
-
mountsourcepath: Mount path format for TiNET/Containerlab file bindings-
"local": Use relative paths for file mounts (standard) -
"abs": Use absolute paths for file mounts
-
-
nodeautoname: Automatic node renaming-
true: Ignore DOT file node names, generate names using NodeClass prefix settings -
false: Use DOT file node names as-is - Uses same mechanism as automatic interface naming
-
dot2net supports automatic naming for multiple object types using prefix-based naming schemes. This ensures consistent, predictable object names across your network configuration.
Always Enabled:
- Interfaces: All interfaces are automatically named using InterfaceClass prefix
- Connections: All connections are automatically named using ConnectionClass prefix
- Network Segments: All detected network segments are automatically named using SegmentClass prefix
Configurable:
-
Nodes: When
nodeautoname: truein global settings, uses NodeClass prefix
| Object Type | Default Prefix | Example Names |
|---|---|---|
| Interface | "net" |
net0, net1, net2
|
| Connection | "conn" |
conn0, conn1, conn2
|
| Segment | "seg" |
seg0, seg1, seg2
|
| Node | "node" |
node0, node1, node2
|
You can customize naming prefixes in class definitions using the prefix attribute:
# Custom interface naming
interfaceclass:
- name: mgmt_interface
prefix: "mgmt" # Generates: mgmt0, mgmt1, mgmt2...
# Custom connection naming
connectionclass:
- name: vlan_trunk
prefix: "trunk" # Generates: trunk0, trunk1, trunk2...
# Custom segment naming
segmentclass:
- name: network_segment
prefix: "net" # Generates: net0, net1, net2...
# Custom node naming (when nodeautoname: true)
nodeclass:
- name: router
prefix: "rtr" # Generates: rtr0, rtr1, rtr2...All automatically named objects can reference their assigned names in templates using {{ .name }}:
# Connection template using auto-assigned name
connectionclass:
- name: vlan_connection
prefix: "vlan"
config:
- name: connection_setup
template:
- "# Connection: {{ .name }}" # Outputs: vlan0, vlan1, etc.
# Segment template using auto-assigned name
segmentclass:
- name: network_segment
prefix: "net"
config:
- name: network_entry
template:
- "- name: {{ .name }}" # Outputs: net0, net1, etc.- Consistency: Sequential numbering ensures predictable naming patterns
-
Template compatibility: All objects support
{{ .name }}template references - Cross-object references: Reliable names enable stable inter-object relationships
- Configuration portability: Generated names work consistently across environments
Define output files and their properties. For detailed explanation, see File Output.
file:
- name: frr.conf
path: /etc/frr/frr.conf # Target path on nodes
scope: node # "node" (per-node, default) or "network" (single file)
format: frr_format # Reference to format definition
output: node # "node" (subdirectory) or "root" (lab root)
name_prefix: "" # Prefix for output filename
name_suffix: "" # Suffix for output filenameDefine text formatting for generated files. dot2net uses a two-phase formatting approach:
format:
- name: frr_format
# Format Phase (applied during config block generation)
format_lineprefix: " "
format_linesuffix: ""
format_lineseparator: "\n"
format_blockprefix: ""
format_blocksuffix: "!"
# Merge Phase (applied when combining multiple blocks)
merge_blockseparator: "\n"
merge_resultprefix: "" # Optional: wrap entire merged result
merge_resultsuffix: "" # Optional: wrap entire merged resultTwo-Phase Processing:
-
Format Phase - Individual config block formatting:
-
format_lineprefix: Added before each line -
format_linesuffix: Added after each line -
format_lineseparator: Used to join lines (default:"\n") -
format_blockprefix: Added before entire config block -
format_blocksuffix: Added after entire config block
-
-
Merge Phase - Combining multiple formatted blocks:
-
merge_blockseparator: Used to join multiple config blocks (default:"\n") -
merge_resultprefix: Added before the entire merged result (optional) -
merge_resultsuffix: Added after the entire merged result (optional)
-
Backward Compatibility (v0.6.x):
Legacy field names are still supported for compatibility but will be removed in v0.7.0:
-
lineprefix→format_lineprefix -
linesuffix→format_linesuffix -
lineseparator→format_lineseparator -
blockprefix→format_blockprefix -
blocksuffix→format_blocksuffix -
blockseparator→merge_blockseparator
Real-world examples:
# FRR vtysh command format
format:
- name: frr_vtysh
format_lineseparator: "\" -c \""
format_blockprefix: "vtysh -c \"conf t\" -c \""
format_blocksuffix: "\""
# Containerlab YAML array format
format:
- name: clab_yaml
merge_blockseparator: ", "
# Containerlab command list format
format:
- name: clab_cmd
format_lineprefix: " - "
merge_blockseparator: "\n"Complete example demonstrating all attributes:
format:
- name: comprehensive_format
# Format Phase
format_lineprefix: " " # Indent each line
format_linesuffix: ";" # Add semicolon to each line
format_lineseparator: " \\\n" # Line continuation with backslash
format_blockprefix: "START {\n" # Block opening
format_blocksuffix: "\n} END" # Block closing
# Merge Phase
merge_blockseparator: "\n---\n" # Separator between blocks
merge_resultprefix: "# BEGIN\n" # Wrap entire result
merge_resultsuffix: "\n# END" # Wrap entire resultProcessing flow example:
Input template: ["router ospf", "network 10.0.1.0/24 area 0"]
↓ Format Phase - formatConfigLines (comprehensive_format)
Step 1 - Apply line formatting (format_lineprefix/suffix/separator):
" router ospf; \\\n network 10.0.1.0/24 area 0;"
↓ Format Phase - formatSingleConfigBlock
Step 2 - Apply block formatting (format_blockprefix/suffix):
"START {\n router ospf; \\\n network 10.0.1.0/24 area 0;\n} END"
↓ Merge Phase - mergeConfigBlocks (multiple blocks)
Step 3 - Join blocks with merge_blockseparator:
"Block1\n---\nBlock2\n---\nBlock3"
↓ Merge Phase - wrap result (merge_resultprefix/suffix)
Step 4 - Wrap entire result:
"# BEGIN\nBlock1\n---\nBlock2\n---\nBlock3\n# END"
When Merge Phase is used:
- Sorter templates (
style: sort) that combine multiple config blocks -
blocks.before/blocks.afterfeatures that merge child configs
Define protocol layers and IP policies:
layer:
- name: ip
default_connect: true # Default layer for connections
policy:
- name: ip
range: 10.0.0.0/16
prefix: 24
- name: lo
type: loopback
range: 10.0.255.0/24Key attributes:
-
name: Layer identifier (used in template variables) -
default_connect: Default connection layer for IP segment discovery-
true: ConnectionClasses without explicit layer specification are considered connected on this layer -
false: Not used for default connections - Used by
DefaultConnectionLayer()function for segment exploration
-
-
policy: Array of IP address policies for this layer
IP Policy attributes:
-
name: Policy identifier -
type: Policy type ("ip"for normal interfaces,"loopback"for loopback interfaces) -
range: IP address range (CIDR notation) -
prefix: Default prefix length for subnets
Generated template variables: Each layer automatically provides template variables:
-
{{ .{name}_addr }}- IP address -
{{ .{name}_net }}- Network address -
{{ .{name}_plen }}- Prefix length -
{{ .{name}_protocol }}- Protocol identifier -
{{ .{name}_loopback }}- Loopback address
Example usage:
# Template can use:
template:
- "interface {{ .name }}"
- " ip address {{ .ip_addr }}/{{ .ip_plen }}"
- " description Connected to {{ .ip_net }}"Configure management network independent of main topology (optional):
mgmt_layer:
name: mgmt # Layer name identifier
range: 192.168.1.0/24 # IP address range for management interfaces
gateway: 192.168.1.1 # External gateway (reserved from auto-assignment)
interface_name: mgmt0 # Management interface name (default: "mgmt0")Key attributes:
-
name: Management layer identifier (used in template variables) -
range: IP address range for automatic assignment to management interfaces -
gateway: External gateway address (automatically reserved from assignment pool) -
interface_name: Name for management interface on each node (default:"mgmt0")
Behavior:
- Independent of topology: Management interfaces are automatically created on every node
- Separate IP space: Uses dedicated IP range independent of main network layers
- External connectivity: Designed for out-of-band management (Containerlab external networks)
-
Automatic creation: Management interfaces added during
addSpecialInterfaces()processing
Generated template variables:
-
{{ .{name}_addr }}- Management IP address -
{{ .{name}_net }}- Management network address -
{{ .{name}_plen }}- Management prefix length
Usage with Containerlab: Management layer integrates with Containerlab's external network connectivity for out-of-band device management.
Example:
mgmt_layer:
name: mgmt
range: 10.255.255.0/24
gateway: 10.255.255.1
interface_name: eth0This creates eth0 management interface on each node with automatic IP assignment from 10.255.255.0/24 range.
Define automatic parameter assignment:
param_rule:
- name: vlan_id
assign: segment # "object" (default), "segment", "connection"
layer: ip # Required when assign: "segment"
type: integer # "integer" (default) or "file"
min: 100
max: 1001
header: vlan # Prefix for generated values
footer: "" # Suffix for generated values
- name: conn_id
assign: connection
header: conn
min: 0
- name: hostname_list
type: file
sourcefile: ./hostnames.txt # Read values from fileKey attributes:
-
name: Parameter rule identifier (must match parameter names in class definitions) -
assign: Assignment scope-
"object"(default): Individual assignment per node/interface -
"segment": Same value for interfaces in the same network segment -
"connection": Same value for interfaces connected by the same connection
-
-
layer: Protocol layer specification (required whenassign: "segment") -
type: Parameter generation type-
"integer"(default): Generate numeric sequences -
"file": Read values from external file
-
Integer type attributes:
-
min: Starting value (default: 0) -
max: Maximum value (optional, for validation) -
header: Prefix string (default: "") -
footer: Suffix string (default: "") -
Generation pattern:
{header}{min+i}{footer}
File type attributes:
-
sourcefile: Path to source file (relative to config file) - Format: One value per line, read sequentially
Assignment behavior examples:
# Example: VLAN assignment per segment
param_rule:
- name: vlan_id
assign: segment
layer: ip
min: 100
header: vlan
# Result: vlan100, vlan101, vlan102... (same value for all interfaces in each segment)
# Example: Connection ID per connection
param_rule:
- name: conn_id
assign: connection
header: conn
min: 0
# Result: conn0, conn1, conn2... (same value for both ends of each connection)
# Example: Individual interface numbering
param_rule:
- name: if_num
assign: object # or omit (default)
min: 1
# Result: 1, 2, 3... (unique value per interface)The Value class allows attaching multiple parameter sets to a single object. This is useful for scenarios like:
- Multiple VLAN configurations per switch
- Multiple static routes per router
- Dynamic file mount configurations
Basic Structure:
param_rule:
- name: vlan_ids
mode: attach # Required for Value class
source:
type: range # "range", "sequence", "list", or "file"
start: 100
end: 103
param_format:
vlan_id: "{{ .value }}"
config:
- name: vlan_entry
template:
- "vlan {{ .vlan_id }}"Mode:
-
distribute(default): One value per object (legacy behavior) -
attach: Multiple Values attached to one object
Source Types:
| Type | Description | Fields |
|---|---|---|
range |
Numeric range |
start, end
|
sequence |
Formatted sequence |
start, end, format
|
list |
Explicit value list |
values (array) |
file |
Values from file | path |
Template Reference:
In class config templates, reference Values using values_ prefix:
node_class:
- name: switch
params: [vlan_ids] # Reference the param_rule
config:
- name: startup
template:
- "! VLAN Configuration"
- "{{ .values_vlan_entry }}" # Reference formatted Value outputComplete Example:
# Define param_rule with attach mode
param_rule:
- name: static_routes
mode: attach
source:
type: list
values:
- { network: "10.0.0.0/8", gateway: "192.168.1.1" }
- { network: "172.16.0.0/12", gateway: "192.168.1.2" }
config:
- name: route_entry
template:
- "ip route {{ .network }} {{ .gateway }}"
# Reference in node class
node_class:
- name: router
params: [static_routes]
config:
- file: router.conf
template:
- "! Static Routes"
- "{{ .values_route_entry }}"Module Generators:
Modules can provide generators for dynamic Value creation:
# Containerlab module provides clab.filemounts generator
# TiNET module provides tinet.filemounts generator
# These are used internally for bind mount generationLoad external modules. For details on how modules work, see Module System.
module:
- tinet # TiNET spec.yaml generation
- containerlab # Containerlab topo.yaml generation
- frr # FRR configuration helpersdot2net uses a comprehensive class system to organize network objects and their configurations:
NetworkClass defines network-wide configuration:
networkclass:
- name: main_network
values:
project: "example_network"
version: "1.0"
config:
- file: network_info.txt
template:
- "# Network: {{ .project }} v{{ .version }}"NodeClass defines device types and their basic properties:
nodeclass:
- name: router
virtual: false # true = exclude from final output files
values:
kind: linux
image: quay.io/frrouting/frr:8.5.0
interface_policy: [ip]
params: [lo]
config:
- file: frr.conf
template:
- "router ospf"
- " ospf router-id {{ .ip_loopback }}"Key attributes:
-
virtual: true- Exclude from deployment files (useful for topology modeling) -
values- Default parameter values -
interface_policy- IP assignment policies for interfaces -
params- Parameter rules for automatic assignment -
config- Configuration template blocks
InterfaceClass defines interface types and behaviors:
interfaceclass:
- name: vlan
layers: [ip] # Restrict to specific layers
params: [vlan]
config:
- group: params.txt
priority: -1 # Processing priority (lower = earlier)
template:
- "vlan {{ .vlan }} for {{ .node_name }}.{{ .name }}"Key attributes:
-
layers- Specify which protocol layers this class applies to -
priority- Control processing order within groups -
group- Accumulate configuration blocks for later merging -
neighbors- Reference adjacent interfaces for iterative configuration -
classmembers- Reference objects in the same class for member-based configuration
ConnectionClass defines connection types and properties (new specification):
connectionclass:
- name: vlan_conn
prefix: "vlan_trunk" # Auto-naming prefix for connections
params: [conn_id, vlan_id] # Auto-assigned by parameter rules
config:
- group: network_config.txt
priority: -2
template:
- "# VLAN Connection: {{ .name }} (ID: {{ .conn_id }}, VLAN: {{ .vlan_id }})"
- "connection {{ .name }} type vlan_trunk vlan {{ .vlan_id }}"Key attributes:
-
prefix- Automatic naming prefix (generates names likevlan_trunk0,vlan_trunk1) -
params- Parameter rules for automatic value assignment - Connection templates use
{{ .name }}for self-reference
SegmentClass defines network segment configurations (new specification):
segmentclass:
- name: network_segment
layer: ip
prefix: "net" # Auto-naming prefix for segments
params: [segment_id] # Auto-assigned by parameter rules
config:
- name: network_entry
template:
- "- name: {{ .name }}" # Auto-assigned segment name
- " vlan: auto"
- " nodes:"
- "{{ .interfaces_segment_nodes }}"Key attributes:
-
layer- Protocol layer for this segment type -
prefix- Automatic naming prefix (generates names likenet0,net1) -
params- Parameter rules for automatic value assignment - Segments are automatically detected from network topology
- Segment templates use
{{ .name }}for self-reference - Used with relational class labels (
segment#class_name)
GroupClass defines logical groupings (subnets, ASes, clusters):
groupclass:
- name: backbone_area
virtual: false # true = exclude from final output files
params: [ospf_area_id] # Parameter rules for automatic assignment
values:
area_type: "backbone"
priority: "high"
config:
- file: area_config.txt
template:
- "# OSPF Area {{ .ospf_area_id }} ({{ .area_type }})"
- "area {{ .ospf_area_id }} authentication"Key attributes:
-
virtual- Exclude from final output if true -
params- Parameter rules for automatic assignment -
values- Default parameter values - Used for logical network organization (DOT subgraphs)
dot2net supports two template description styles for assembling configuration templates. For conceptual understanding of when to use each approach, see Template System - Template Assembly Approaches.
ConfigTemplates can be coordinated in several ways:
| Mechanism | Purpose | Description |
|---|---|---|
| Hierarchical | Template embedding | Embed child templates via {{ .self_xxx }} or {{ .interfaces_xxx }}
|
| Sort | Group aggregation | Collect templates into groups, then merge with sorting |
| blocks.before/after | Output ordering | Control position of blocks relative to other templates |
| required_params | Conditional output | Skip entire block if parameters are missing |
| depends | Processing order | Required for same-object template embedding (e.g., {{ .self_xxx }}) |
Typical combinations:
- Hierarchical + blocks: Use Hierarchical for embedding, blocks for cross-class ordering (e.g., interface configs before router section)
- Sort + blocks: Aggregate by priority, with additional ordering constraints
- Any style + required_params: Add conditional output to optional configuration sections
Default approach with strict template relationship management:
config:
- file: ospfd.conf
template:
- "router ospf"
- " ospf router-id {{ .RouterID }}"
- " {{ .interfaces_ospf_network }}" # Embedded template positionCharacteristics:
- Strict ordering: Template embedding positions must be explicitly defined
- Precise relationships: Template dependencies are strictly managed
- Complex control: Supports intricate dependency relationships
Advantages:
- Strict order control
- Clear template relationships
- Accurate expression of complex dependencies
Disadvantages:
- More complex to write
- Requires detailed position specification
Alternative approach using loose relationship management with Group Templates + Sorter Templates:
Accumulate configuration blocks for later processing:
config:
- group: "ospf6d.conf"
priority: -1 # Order control via priority only
template:
- "log file /var/log/frr.log"Merge and output accumulated group configurations:
config:
- file: "ospf6d.conf"
style: sort
sort_group: "ospf6d.conf" # References group name
template:
- "router ospf6"
- " ospf6 router-id {{ .RouterID }}"Characteristics:
- Simple addition: Just add templates to defined groups
- Loose management: Template relationships are loosely controlled
- Priority-based ordering: Order control through priority values only
Advantages:
- Simple description
- Easy template addition
- Flexible management approach
Disadvantages:
- Difficult to express strict dependencies
- Not suitable for complex order control
Core mechanism for template embedding relationships in Hierarchical style:
config:
- name: "base_config"
template:
- "base settings"
- name: "advanced_config"
depends: ["base_config"] # Required for same-object template dependencies
template:
- "advanced settings"
- "{{ .base_config }}" # Template embeddingDependency Requirements:
-
Cross-object embedding (Parent-Child relationships):
# NodeClass template embedding InterfaceClass templates template: - "interface configuration:" - "{{ .interfaces_config }}" # No depends needed - hierarchy is clear
-
Same-object embedding (Same-level templates):
# Templates within the same object class config: - name: "base" template: ["base settings"] - name: "extended" depends: ["base"] # Required - processing order matters template: ["{{ .base }}", "extended settings"]
Purpose:
- Essential for Hierarchical style: All template relationships require named templates
- depends required only for same-object template dependencies (reorderConfigTemplates processing)
- Parent-child class relationships have implicit dependencies through object hierarchy
The required_params field allows templates to be conditionally skipped when specified parameters are missing or empty:
nodeclass:
- name: router
config:
# Always output
- name: base_config
template: ["hostname {{ .name }}"]
# Only output if 'mem' parameter exists and is non-empty
- name: memory_config
required_params: [mem]
template: ["memory {{ .mem }}"]
# Only output if both 'cpus' AND 'sysctl' exist
- name: resource_config
required_params: [cpus, sysctl]
template:
- "cpus {{ .cpus }}"
- "sysctl {{ .sysctl }}"Behavior:
- If all parameters in
required_paramsexist and are non-empty → template is processed - If any parameter is missing or empty → entire template block is skipped
- Empty string values are treated as "not exists"
Use cases:
- Optional parameters (mem, cpus, sysctl) in container configs
- Module-provided templates that depend on user-defined parameters
- Avoiding if-statements in templates for cleaner, declarative configuration
Comparison with template if-statements:
| Approach | Pros | Cons |
|---|---|---|
required_params |
Declarative, no template logic | Block-level only |
{{ if .param }} |
Fine-grained control | Template becomes complex |
Note: required_params checks both regular parameters and relative parameters (e.g., self_startup, values_*).
The blocks field controls where a template's output is positioned relative to other templates:
nodeclass:
- name: router
config:
# Main router config - other blocks position relative to this
- name: router_base
file: frr.conf
template:
- "router ospf"
- " router-id {{ .ip_loopback }}"
interfaceclass:
- name: default
config:
# Interface config should appear BEFORE router_base in frr.conf
- name: interface_config
file: frr.conf
blocks:
before: [router_base]
template:
- "interface {{ .name }}"
- " ip address {{ .ip_addr }}/{{ .ip_plen }}"
# Network statements should appear AFTER router_base
- name: ospf_network
file: frr.conf
blocks:
after: [router_base]
template:
- " network {{ .ip_net }} area 0"Result in frr.conf:
interface net0
ip address 10.0.0.1/24
interface net1
ip address 10.0.0.5/24
router ospf
router-id 10.255.0.1
network 10.0.0.0/24 area 0
network 10.0.0.4/24 area 0
Behavior:
-
blocks.before: [name1, name2]- This template's output appears before the listed templates -
blocks.after: [name1, name2]- This template's output appears after the listed templates - Multiple templates can be listed; ordering is determined by dependency resolution
- Works across different object classes (e.g., InterfaceClass referencing NodeClass templates)
Use cases:
- FRR/Quagga configs where interface definitions must precede router sections
- Any config format requiring specific section ordering
- Separating logical config sections while maintaining correct output order
Relationship with depends:
-
dependscontrols processing order (template A must be evaluated before template B) -
blocks.before/aftercontrols output order (template A's output appears before/after template B's output) - Both can be used together when needed
Templates have access to a symmetric parameter namespace:
-
{{ .name }}- Object name -
{{ .ip_addr }}- IP address -
{{ .ip_plen }}- IP prefix length -
{{ .vlan_id }}- VLAN identifier
Templates can reference related objects with consistent prefixes:
template:
- "interface {{ .name }}"
- " description Connected via {{ .conn_name }}"
- " vlan {{ .conn_vlan_id }}"template:
- "interface {{ .name }}"
- " description Interface on {{ .node_name }}"
- " ip address {{ .ip_addr }}/{{ .ip_plen }}"template:
- "connection {{ .name }}"
- " type vlan_trunk"
- " vlan {{ .vlan_id }}"-
Connection templates: Use
{{ .name }}for self-reference -
Interface templates: Use
{{ .conn_name }}for connection reference -
Consistent prefixing: All connection references use
conn_prefix, node references usenode_prefix
Network → Node → Connection → Interface → Group → Segment
Critical: Connection parameters must be assigned before Interface parameters to enable cross-object references.
-
Dependency Resolution:
reorderConfigTemplatesresolves template dependencies - Group Processing: Group templates accumulate configuration blocks
- Sorter Processing: Sorter templates merge and output final configurations
- Priority Control: Lower priority values (-3, -2, -1) process first
- Interface namespace includes connection parameters with
conn_prefix - Interface namespace includes node parameters with
node_prefix - References are established during parameter assignment phase
-
Virtual Nodes: Use
virtual: truefor topology modeling without deployment - Modular Extension: Use multiple classes for additional functionality
- Clear Naming: Use descriptive class names that reflect their purpose
-
Deterministic Templates: Avoid control syntax (
for,if) - use parameter symmetry instead -
Consistent Prefixing: Use
conn_andnode_prefixes for cross-object references - Priority Management: Use negative priorities for foundational configurations
- Automatic Assignment: Leverage parameter rules for consistent value assignment
- Manual Override: Use direct value assignment in DOT files when needed
- Cross-Object Consistency: Maintain consistent naming across related objects
nodeclass:
- name: router
values:
kind: linux
image: quay.io/frrouting/frr:8.5.0
params: [lo]
connectionclass:
- name: vlan_conn
prefix: "vlan_trunk"
params: [conn_id, vlan_id]
config:
- group: network_config.txt
priority: -2
template:
- "# Connection: {{ .name }} VLAN {{ .vlan_id }}"
interfaceclass:
- name: trunk_interface
config:
- group: interface_config.txt
priority: -1
template:
- "interface {{ .name }}"
- " description Trunk to {{ .opp_node_name }} via {{ .conn_name }}"
- " switchport mode trunk"
- " switchport trunk allowed vlan {{ .conn_vlan_id }}"
segmentclass:
- name: trunk_segment
layer: ip
config:
- group: network_config.txt
priority: -3
template:
- "# Trunk Segment: {{ .segment_name }} with {{ .segment_interface_count }} interfaces"digraph {
r1 [xlabel="router"];
r2 [xlabel="router"];
r1 -> r2 [
dir="none",
class="vlan_conn; segment#trunk_segment",
taillabel="trunk_interface",
headlabel="trunk_interface"
];
}This configuration demonstrates the complete workflow from class definition to cross-object references, showcasing dot2net's powerful template and parameter system.
Interfaces can reference adjacent interfaces through neighbors configuration for iterative template processing:
interfaceclass:
- name: ospf_interface
neighbors:
- layer: ip # Process neighbors on IP layer
config:
- name: neighbor_config
template:
- "# Neighbor: {{ .opp_node_name }} via {{ .conn_name }}"
- "neighbor {{ .opp_ip_addr }} area {{ .ospf_area }}"Key features:
-
Interface-specific: Only InterfaceClass supports
neighbors - Layer-based: Process neighbors on specific protocol layers
- Automatic iteration: Template executes for each adjacent interface
-
Neighbor parameters: Access
{{ .opp_* }}parameters for opposite interface
Multiple object types can reference other objects in the same class through classmembers:
nodeclass:
- name: router_cluster
classmembers:
- nodes: ["router"] # Reference other nodes with class "router"
config:
- name: cluster_peers
template:
- "# Cluster peer: {{ .name }} at {{ .ip_loopback }}"
- "peer {{ .ip_loopback }} cluster-member"interfaceclass:
- name: trunk_ports
classmembers:
- interfaces: ["trunk_interface"] # Reference interfaces in same class
include_self: false # Exclude current interface from iteration
config:
- name: trunk_aggregation
template:
- "# Trunk peer: {{ .node_name }}.{{ .name }}"
- "trunk-peer {{ .node_name }} interface {{ .name }}"connectionclass:
- name: vlan_connection
classmembers:
- connections: ["vlan_conn"] # Reference connections in same class
config:
- name: vlan_coordination
template:
- "# VLAN peer connection: {{ .name }} VLAN {{ .vlan_id }}"segmentclass:
- name: network_segment
classmembers:
- nodes: ["router"] # Reference nodes within the segment
config:
- name: segment_routing
template:
- "# Segment node: {{ .name }} in segment {{ .segment_name }}"
- "segment-id {{ .segment_id }} node {{ .name }}"Supported object types for classmembers:
-
NodeClass: Can reference
nodes,interfaces,connections -
InterfaceClass: Can reference
nodes,interfaces,connections -
ConnectionClass: Can reference
nodes,interfaces,connections -
SegmentClass: Can reference
nodes,interfaces,connections
Key attributes:
-
nodes/interfaces/connections- Specify which object classes to reference -
node/interface/connection- Single class name (alternative syntax) -
include_self- Whether to include the current object in iteration (default: true) -
config- Template blocks that execute for each referenced object