Subnetter Architecture
This document provides detailed technical information about Subnetter’s architecture. It is intended for developers who want to understand the system’s internal workings or contribute to the codebase.
1. System Overview
Subnetter is a tool for allocating IPv4 CIDR blocks across cloud infrastructure in a hierarchical, deterministic manner. It takes a configuration file as input and produces a set of non-overlapping CIDR allocations for subnets across multiple cloud providers, accounts, regions, and availability zones.
The tool is designed to be:
- Deterministic: The same input configuration always produces the same output allocations
- Hierarchical: CIDRs are allocated in a nested structure (accounts → regions → AZs → subnets)
- Non-overlapping: All allocated CIDRs are guaranteed not to overlap
- Cloud-agnostic: Works with AWS, Azure, GCP, and other cloud providers
- Flexible: Supports various configuration options and output formats
Current Implementation Status: The core CIDR allocation functionality is fully implemented across all supported cloud providers (AWS, Azure, and GCP). The tool offers comprehensive configuration options and error handling, with additional features planned as outlined in the roadmap.
1.1 CIDR Allocation Hierarchy
1.2 High-Level Data Flow
2. Configuration System
2.1 Configuration Structure
The configuration file is the primary input to the system and defines the structure of the CIDR allocation hierarchy.
Key sections of the configuration include:
- Base CIDR block
- Account definitions
- Region specifications
- Subnet type definitions
- Prefix length settings
2.2 Validation Rules and Constraints
The configuration validation system enforces a set of rules to ensure that inputs will result in valid and practical CIDR allocations. These constraints are implemented as a schema using Zod in packages/core/src/config/schema.ts
.
Key validation rules:
- Base CIDR: Must be a valid CIDR notation (e.g.,
10.0.0.0/8
) - Subnet Types: Must be a non-empty object with valid subnet type names and prefix lengths
- Accounts: Must be a non-empty array of account objects with valid names and cloud configurations
- Prefix Lengths: Must be a valid object with account, region, and AZ prefix lengths within the valid range (8-28)
2.3 Schema Evolution and Backwards Compatibility
As the tool evolves, the configuration schema may change over time. We’ve designed the system to maintain backwards compatibility with older configuration formats where possible. This section describes our approach to schema evolution.
Key principles for backwards compatibility:
- Additive Schema Changes: New fields should be added in a way that doesn’t break existing configurations
- Schema Versioning: Major changes to the schema should increment the major version number
- Format Normalization: Internally normalize different configuration formats to support legacy formats
- Deprecation Cycle: Old formats should go through a deprecation cycle before being removed
Example of schema evolution:
// Original v1 format - array of subnet types"subnetTypes": [ { "name": "Public", "prefixLength": 24 }, { "name": "Private", "prefixLength": 26 }]
// New v2 format - object map of subnet types"subnetTypes": { "Public": 24, "Private": 26}
Both formats are supported through the normalization layer, which converts them to a consistent internal format.
2.4 Configuration Examples
This section provides examples of real-world configurations and their resulting allocations.
Basic Single-Account Configuration
{ "baseCidr": "10.0.0.0/8", "prefixLengths": { "account": 16, "region": 20, "az": 22 }, "subnetTypes": { "Public": 24, "Private": 26, "Data": 28 }, "accounts": [ { "name": "Production", "clouds": { "aws": { "regions": ["us-east-1", "us-west-2"] } } } ]}
Resulting allocations (simplified):
Account: Production, Region: us-east-1, AZ: us-east-1a, Subnet: Public, CIDR: 10.0.0.0/24Account: Production, Region: us-east-1, AZ: us-east-1a, Subnet: Private, CIDR: 10.0.1.0/26Account: Production, Region: us-east-1, AZ: us-east-1a, Subnet: Data, CIDR: 10.0.1.64/28Account: Production, Region: us-east-1, AZ: us-east-1b, Subnet: Public, CIDR: 10.0.4.0/24...
3. Core Components
3.1 CIDR Utilities
The CIDR Utilities layer (packages/cidr-utils
) provides low-level functionality for IP address and CIDR manipulation, including:
- IP Address Parsing: Converting between string, numeric, and octet representations
- CIDR Validation: Ensuring CIDR blocks are valid and well-formed
- Subnet Calculations: Computing subnet properties (network address, broadcast, usable IPs)
- Range Detection: Determining if CIDR blocks overlap or contain one another
- Error Handling: Providing detailed error types for IP and CIDR operations
Key files:
packages/cidr-utils/src/validator.ts
: CIDR validation functionspackages/cidr-utils/src/parser.ts
: CIDR parsing and normalizationpackages/cidr-utils/src/ip.ts
: IP address manipulation utilitiespackages/cidr-utils/src/calculator.ts
: Subnet calculation functionspackages/cidr-utils/src/subnet.ts
: Subnet allocation utilities
This dedicated CIDR utilities package replaces direct dependencies on external libraries like ipaddr.js, providing several advantages:
- Complete control over IP address and CIDR manipulation logic
- Consistent error handling with domain-specific error types
- Performance optimization for Subnetter’s specific use cases
- TypeScript-first design with comprehensive type definitions
- Zero dependencies for better security and smaller bundle size
3.2 CIDR Allocator
The CIDR allocator is the heart of the system, responsible for:
- Dividing the base CIDR block into account-level blocks
- Further subdividing into regions, AZs, and subnets
- Tracking allocated CIDRs to prevent overlaps
- Generating the final allocation objects
Key files:
packages/core/src/allocator/core/allocator.ts
: Main allocator classpackages/core/src/allocator/core/region.ts
: Region-level allocationpackages/core/src/allocator/core/subnet.ts
: Subnet-level allocationpackages/core/src/allocator/utils/cidr/calculator.ts
: CIDR manipulation utilities
3.3 Cloud Provider Detection
The system intelligently detects and handles different cloud providers, applying provider-specific logic where needed:
- AWS: Understands AWS region and AZ naming conventions (us-east-1, us-east-1a)
- Azure: Maps regions to Azure conventions (eastus, eastus-1)
- GCP: Understands GCP zone naming patterns (us-central1, us-central1-a)
Implementation details:
- Provider detection is handled by the
CloudProviderDetector
class - Region normalization ensures consistent handling across providers
- AZ naming is automatically adjusted based on the detected provider
Current Implementation Status: AWS, Azure, and GCP provider support are now fully implemented with complete region and availability zone handling. Additional cloud providers may be added in the future through the planned extensibility framework.
3.4 Algorithm Complexity and Performance
The CIDR allocation algorithm is designed for deterministic, efficient allocation with the following characteristics:
Operation | Time Complexity | Space Complexity |
---|---|---|
Configuration Loading | O(n) | O(n) |
CIDR Validation | O(1) | O(1) |
Account Allocation | O(a) | O(a) |
Region Allocation | O(a*r) | O(a*r) |
AZ Allocation | O(arz) | O(arz) |
Subnet Allocation | O(arz*s) | O(arz*s) |
Total Allocation | O(arz*s) | O(arz*s) |
Where:
- a = number of accounts
- r = average number of regions per account
- z = average number of AZs per region
- s = number of subnet types
Performance considerations:
- The algorithm uses efficient CIDR block calculations
- Allocations are performed in a single pass
- Results are cached to avoid recalculation
3.5 Output Generator
The output generator is responsible for:
- Formatting the allocations into the desired output format (CSV)
- Writing the output to a file or stdout
Key files:
packages/core/src/output/csv-writer.ts
: CSV output generation
4. Core CIDR Allocation System
The CIDR allocation system is the heart of Subnetter. It takes a parsed and validated configuration and generates a complete set of non-overlapping CIDR allocations for all accounts, regions, availability zones, and subnets.
4.1 Allocation Architecture
The allocation architecture follows a hierarchical approach, with two main components:
- HierarchicalAllocator: Manages the overall allocation hierarchy
- ContiguousAllocator: Handles specific CIDR allocations at each level
4.2 Allocation Hierarchy
The allocation process follows this hierarchy:
- Base CIDR: The starting point for all allocations (e.g.,
10.0.0.0/8
) - Account Level: Divides the base CIDR among accounts (typically with
/16
prefix) - Region Level: Subdivides account CIDRs among regions (typically with
/20
prefix) - Availability Zone Level: Subdivides region CIDRs among AZs (typically with
/24
prefix) - Subnet Level: Final division into specific subnet types (with variable prefixes like
/26
,/27
, etc.)
Each level uses a ContiguousAllocator instance to ensure that allocations at that level are contiguous and non-overlapping.
4.3 Contiguous Allocation Algorithm
The ContiguousAllocator implements a sequential allocation algorithm that:
- Starts with a base CIDR block
- Tracks the current allocation position within that block
- Allocates new CIDR blocks sequentially, advancing the position after each allocation
- Ensures all allocations are non-overlapping
- Verifies that there is sufficient space for each allocation
4.4 Hierarchical Allocation Process
The HierarchicalAllocator manages the overall allocation process:
-
Account Processing:
- Checks for account-specific base CIDRs
- Either uses a specified CIDR or allocates from the root allocator
-
Cloud Provider Processing:
- Handles provider-specific configurations
- Processes each cloud provider separately within an account
-
Region Processing:
- Maps to cloud-specific regions
- Allocates CIDR blocks for each region from the account’s allocation
-
Availability Zone Processing:
- Determines the AZs for each region based on provider-specific patterns
- Allocates CIDR blocks for each AZ from the region’s allocation
-
Subnet Processing:
- Creates subnet allocations for each subnet type in each AZ
- Applies subnet-specific prefix lengths
4.5 Allocation Overrides
The allocation system supports several types of overrides:
- Account-Level Overrides: Specify a custom base CIDR for an entire account
- Provider-Level Overrides: Override the base CIDR for a specific cloud provider within an account
- Prefix Length Overrides: Customize the prefix lengths used at each level of the hierarchy
- Subnet Type Overrides: Define different subnet types with specific prefix lengths
These overrides provide flexibility while maintaining the hierarchical structure and preventing overlaps.
4.6 Error Handling
The allocation system includes comprehensive error handling:
- Validation Errors: Detect invalid configurations before allocation starts
- Space Exhaustion Errors: Detect when there’s not enough IP space for requested allocations
- Overlap Detection: Ensure no CIDRs overlap within the hierarchy
- Detailed Context: Provide detailed context information with errors for debugging
5. Project Structure and Workflow
5.1 Monorepo Structure
The project is organized as a monorepo with the following packages:
packages/core
: Core functionality for CIDR allocation and configuration handlingpackages/cli
: Command-line interface for the toolpackages/docs
: Documentation sitepackages/cidr-utils
: Pure JavaScript/TypeScript utilities for CIDR manipulation and subnet calculations
5.1.1 CIDR Utils Package
The CIDR Utils package (packages/cidr-utils
) provides a foundation of low-level utilities for working with IPv4 CIDR notation:
- IP Utilities: Conversion between string, numeric, and octet representations of IP addresses
- CIDR Parser: Functions for parsing and normalizing CIDR notation
- CIDR Validator: Comprehensive validation of CIDR notation with detailed error handling
- Subnet Calculator: Tools for calculating subnet properties, range detection, and subnet allocation
This package is designed to be:
- Dependency-free: Pure JavaScript/TypeScript implementation with no external dependencies
- Reusable: Usable in any JavaScript/TypeScript project requiring CIDR functionality
- Comprehensive: Complete set of utilities for all CIDR-related operations
- Self-contained: Can be used independently of the rest of the Subnetter project
5.1.2 Package Dependency Architecture
The Subnetter project follows a clear dependency hierarchy to maintain separation of concerns and modularity:
The dependency flow is designed to follow best practices for modularity and reusability:
-
CIDR Utils Package: Forms the foundation with no internal dependencies
- Provides low-level CIDR utilities that can be used independently
- Serves as the core building block for IP address manipulation
- Can be used by external projects needing CIDR functionality
-
Core Package: Depends on CIDR Utils
- Implements the business logic for subnet allocation
- Uses CIDR Utils for all IP address and subnet calculations
- Exposes a clean API for programmatic use
-
CLI Package: Depends on Core
- Provides the user interface layer
- Uses the Core package’s API to drive the application
- Does not directly use CIDR Utils to maintain proper layering
This architecture ensures:
- Separation of concerns: Each package has a well-defined responsibility
- Reduced coupling: Dependencies flow in one direction only
- Reusability: Lower-level packages can be used independently
- Maintainability: Changes in one layer don’t affect others unnecessarily
5.2 CLI Interface
The CLI interface provides a user-friendly way to interact with the tool, including:
- Parsing command-line arguments
- Handling errors and providing helpful messages
- Configuring logging levels
Key files:
packages/cli/src/index.ts
: Main CLI entry point
5.3 Data Flow
The following diagram illustrates the complete data flow through the system:
5.4 Testing Approach
The codebase has extensive test coverage:
- Unit tests: For individual functions and classes
- Integration tests: For the complete allocation process
- End-to-end tests: For the CLI interface
Current Implementation Status: The project now has comprehensive test coverage (>90%) across unit, integration, and end-to-end tests. All core functionality has extensive test cases covering both common scenarios and edge cases to ensure reliability and correctness.
5.5 CI/CD Process
The project uses GitHub Actions for CI/CD:
- Build: Compile TypeScript code
- Test: Run unit and integration tests
- Lint: Check code style and quality
- Publish: Publish packages to npm (on release)
6. Data Model
The core data model consists of these key interfaces:
These interfaces define the structure of the configuration input and allocation output.
7. Extensibility and Future Development
7.1 Extensibility Points
The architecture is designed with several extensibility points that allow users to customize and extend the tool without altering the core codebase.
Key extension areas:
- Output Format Extensions: The system is designed to easily add new output formats beyond CSV
- Cloud Provider Extensions: Support for additional cloud providers can be added
- Custom Allocation Strategies: Users can implement custom allocation algorithms
- CLI Extensions: The command-line interface can be extended with new commands
- Integration Points: External tools can integrate with the core library
Current Implementation Status: While the core architecture is designed with extensibility in mind, the formal extension interfaces and plugin system remain under development. The current implementation provides stable APIs for integrating with the core library programmatically, but a proper plugin system for third-party extensions is still on the roadmap.
7.2 Future Development
This architecture document describes the current design of the Subnetter tool and outlines potential extensibility points. For a detailed view of which features are currently implemented, partially implemented, or planned for future releases, please refer to our Project Roadmap.
The roadmap includes:
- Current implementation status of all features
- Development priorities and timeline
- Planned release schedule
- Information on how to contribute to future development
As the project evolves, this architecture document will be updated to reflect major architectural changes and enhancements.