Skip to content

YAML Configuration

sat edited this page Sep 17, 2025 · 33 revisions

YAML Configuration

This page explains the YAML configuration system in dot2net, including class definitions, template syntax, and configuration patterns.

Overview

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.

Top-Level Configuration

Global Settings

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 renaming

Key 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

Automatic Object Naming

dot2net supports automatic naming for multiple object types using prefix-based naming schemes. This ensures consistent, predictable object names across your network configuration.

Supported Object Types

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: true in global settings, uses NodeClass prefix

Default Prefixes

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

Custom Prefix Configuration

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...

Template Name References

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.

Benefits

  • 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

Files Configuration

Define output files and their properties:

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

File Formats

Define text formatting for generated files:

format:
  - name: frr_format
    lineprefix: " "
    linesuffix: ""
    lineseparator: "\n"
    blockprefix: ""
    blocksuffix: "!"
    blockseparator: "\n"

Processing stages and attribute application:

  1. Line-level formatting (formatConfigLines):

    • lineprefix: Added before each line
    • linesuffix: Added after each line
    • lineseparator: Used to join lines (default: "\n")
  2. Block-level formatting (formatSingleConfigBlock):

    • blockprefix: Added before entire config block
    • blocksuffix: Added after entire config block
  3. Block merging (mergeConfigBlocks):

    • blockseparator: Used to join multiple config blocks (default: "\n")

Real-world examples:

# FRR vtysh command format
format:
  - name: frr_vtysh
    lineseparator: "\" -c \""
    blockprefix: "vtysh -c \"conf t\" -c \""
    blocksuffix: "\""

# Containerlab YAML array format
format:
  - name: clab_yaml
    blockseparator: ", "

# Containerlab command list format
format:
  - name: clab_cmd
    lineprefix: "      - "
    blockseparator: "\n"

Complete example demonstrating all attributes:

format:
  - name: comprehensive_format
    lineprefix: "  "           # Indent each line
    linesuffix: ";"            # Add semicolon to each line
    lineseparator: " \\\n"     # Line continuation with backslash
    blockprefix: "START {\n"   # Block opening
    blocksuffix: "\n} END"     # Block closing
    blockseparator: "\n---\n"  # Separator between blocks

Processing flow example:

Input template: ["router ospf", "network 10.0.1.0/24 area 0"]

↓ formatConfigLines (comprehensive_format)
Step 1 - Apply line formatting:
  "  router ospf; \\\n  network 10.0.1.0/24 area 0;"

↓ formatSingleConfigBlock
Step 2 - Apply block formatting:
  "START {\n  router ospf; \\\n  network 10.0.1.0/24 area 0;\n} END"

↓ mergeConfigBlocks (multiple blocks)
Step 3 - Merge with block separator:
  "Block1\n---\nBlock2\n---\nBlock3"

Layers Configuration

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/24

Key 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 }}"

Management Layer

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: eth0

This creates eth0 management interface on each node with automatic IP assignment from 10.255.255.0/24 range.

Parameter Rules

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 file

Key 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 when assign: "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)

Module Configuration

Load external modules:

module:
  - tinet
  - containerlab
  - frr

Class System

dot2net uses a comprehensive class system to organize network objects and their configurations:

NetworkClass Definition

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 Definition

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 Definition

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 Definition

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 like vlan_trunk0, vlan_trunk1)
  • params - Parameter rules for automatic value assignment
  • Connection templates use {{ .name }} for self-reference

SegmentClass Definition

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 like net0, 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 Definition

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)

Template Description Styles

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.

Hierarchical Style (Standard)

Default approach with strict template relationship management:

config:
  - file: ospfd.conf
    template:
      - "router ospf"
      - " ospf router-id {{ .RouterID }}"
      - " {{ .interfaces_ospf_network }}"  # Embedded template position

Characteristics:

  • 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

Sort Style

Alternative approach using loose relationship management with Group Templates + Sorter Templates:

Group 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"

Sorter Templates

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

Named Templates (Hierarchical Mechanism)

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 embedding

Dependency Requirements:

  1. Cross-object embedding (Parent-Child relationships):

    # NodeClass template embedding InterfaceClass templates
    template:
      - "interface configuration:"
      - "{{ .interfaces_config }}"  # No depends needed - hierarchy is clear
  2. 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

Template Variables and Cross-Object References

Basic Parameters

Templates have access to a symmetric parameter namespace:

  • {{ .name }} - Object name
  • {{ .ip_addr }} - IP address
  • {{ .ip_plen }} - IP prefix length
  • {{ .vlan_id }} - VLAN identifier

Cross-Object References (New Specification)

Templates can reference related objects with consistent prefixes:

Interface Templates Referencing Connections

template:
  - "interface {{ .name }}"
  - " description Connected via {{ .conn_name }}"
  - " vlan {{ .conn_vlan_id }}"

Interface Templates Referencing Nodes

template:
  - "interface {{ .name }}"
  - " description Interface on {{ .node_name }}"
  - " ip address {{ .ip_addr }}/{{ .ip_plen }}"

Connection Templates (Self-Reference)

template:
  - "connection {{ .name }}"
  - " type vlan_trunk"
  - " vlan {{ .vlan_id }}"

Variable Naming Rules

  • 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 use node_ prefix

Configuration Processing Flow

1. Parameter Assignment Order

Network → Node → Connection → Interface → Group → Segment

Critical: Connection parameters must be assigned before Interface parameters to enable cross-object references.

2. Template Processing Order

  1. Dependency Resolution: reorderConfigTemplates resolves template dependencies
  2. Group Processing: Group templates accumulate configuration blocks
  3. Sorter Processing: Sorter templates merge and output final configurations
  4. Priority Control: Lower priority values (-3, -2, -1) process first

3. Cross-Object Reference Setup

  • Interface namespace includes connection parameters with conn_ prefix
  • Interface namespace includes node parameters with node_ prefix
  • References are established during parameter assignment phase

Best Practices

Class Design

  1. Virtual Nodes: Use virtual: true for topology modeling without deployment
  2. Modular Extension: Use multiple classes for additional functionality
  3. Clear Naming: Use descriptive class names that reflect their purpose

Template Design

  1. Deterministic Templates: Avoid control syntax (for, if) - use parameter symmetry instead
  2. Consistent Prefixing: Use conn_ and node_ prefixes for cross-object references
  3. Priority Management: Use negative priorities for foundational configurations

Parameter Management

  1. Automatic Assignment: Leverage parameter rules for consistent value assignment
  2. Manual Override: Use direct value assignment in DOT files when needed
  3. Cross-Object Consistency: Maintain consistent naming across related objects

Example: Complete VLAN Configuration

YAML Configuration

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"

DOT Usage

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.

Advanced Object References

Neighbor References (Interface-only)

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

Class Member References (Multi-object)

Multiple object types can reference other objects in the same class through classmembers:

Node Class Members

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"

Interface Class Members

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 }}"

Connection Class Members

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 }}"

Segment Class Members

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

Clone this wiki locally