Skip to content

Conversation

l0crian1
Copy link
Contributor

Change summary

This PR will add support for configuring ZeroTier from within the VyOS CLI. In addition to a simple ZeroTier interface, the ability to fully configure options within ZeroTier's local.conf has been added.

The following command trees have been created:

Conf mode:

set interfaces zerotier
└── zerotier
    └── <interface>
        ├── allow-mgmt-from
        ├── bonding-policy
        ├── controller-api-key
        ├── controller-api-url
        ├── custom-policy
        │   └── <policy-name>
        │       ├── base-policy
        │       ├── down-delay
        │       ├── failover-interval
        │       ├── link-quality
        │       │   ├── latency-weight
        │       │   ├── max-latency
        │       │   ├── max-variance
        │       │   └── variance-weight
        │       ├── links
        │       │   └── <interface>
        │       │       ├── capacity
        │       │       ├── failover-to
        │       │       ├── ip-pref
        │       │       └── mode
        │       ├── link-select-method
        │       └── up-delay
        ├── description
        ├── disable
        ├── disable-port-mapping
        ├── disable-secondary-port
        ├── disable-tcp-fallback
        ├── force-tcp-relay
        ├── interface-blacklist
        ├── listen-address
        ├── low-bandwidth-mode
        ├── multicore-options
        │   ├── core-count
        │   ├── cpu-pinning
        │   └── enabled
        ├── multipath-mode
        ├── network-config
        │   └── <network/cidr>
        │       ├── blacklist
        │       └── mtu
        ├── network-id
        ├── peer-config
        │   └── <node-id>
        │       ├── blacklist
        │       └── try
        ├── peer-specific-bonds
        │   └── <node-id>
        │       └── bonding-policy
        ├── primary
        │   └── port
        ├── secondary
        │   └── port
        ├── tcp-relay
        └── tertiary
            └── port

Op mode:

show interfaces zerotier
└── zerotier
    └── <interface>
        ├── bond
        │   ├── json
        │   └── <node-id>
        │       └── json
        ├── info
        │   └── json
        ├── networks
        │   └── json
        ├── peers
        │   └── json
        ├── peers-all
        │   └── detail
        └── peers-detail
            └── detail
restart zerotier interface
└── zerotier
    └── interface
        └── <interface>
import zerotier interface-config
└── zerotier
    └── interface-config
        └── <archived config directory>
delete zerotier interface-config
└── zerotier
    └── interface-config
        └── <interface>
set zerotier interface
└── zerotier
    └── interface
        └── <interface>
            └── network-id
                └── <network-id>
                    ├── allow-default
                    │   ├── disable
                    │   └── enable
                    ├── allow-dns
                    │   ├── disable
                    │   └── enable
                    ├── allow-global
                    │   ├── disable
                    │   └── enable
                    └── allow-managed
                        ├── disable
                        └── enable

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes)
  • Migration from an old Vyatta component to vyos-1x, please link to related PR inside obsoleted component
  • Other (please describe):

Related Task(s)

https://vyos.dev/T6455

Related PR(s)

vyos/vyos-build#1041

How to test / Smoketest result

  1. Create an account on ZeroTier Central (https://my.zerotier.com/)
  2. Create a network within the ZeroTier Central controller
  3. Configure a ZeroTier interface within VyOS:
set interfaces zerotier zt1 description 'test zerotier interface'
set interfaces zerotier zt1 network-id '0123456789abcdef'
set interfaces zerotier zt1 primary port '9994'
  1. Authorize the node in ZeroTier Central
  2. Verify interface is created. The interfaces will be subinterfaces of the configured interface, with the value at the end being a partial string of the network-id. Multiple networks can be joined per interface.
vyos@vyos# run show interfaces | strip-private
Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down
Interface    IP Address          MAC                VRF        MTU  S/L    Description
-----------  -----------------   -----------------  -------  -----  -----  -------------
eth0         -                   xx:xx:xx:xx:xx:e6  default   1500  u/u
eth1         xxx.xxx.101.245/24  xx:xx:xx:xx:xx:23  default   1500  u/u
eth2         -                   xx:xx:xx:xx:xx:19  default   1500  A/D
lo           xxx.xxx.0.1/8       xx:xx:xx:xx:xx:00  default  65536  u/u
             ::1/128             
zt1.272f5    xxx.xxx.177.149/16  xx:xx:xx:xx:xx:01  default   2800  u/u
  1. Check if service is online:
vyos@vyos# run show interfaces zerotier zt1 info | strip-private
200 info cc6xxxxxxx 1.16.0 ONLINE
  1. Check if peers are present:
vyos@vyos# run show interfaces zerotier zt1 peers | strip-private
200 peers
<ztaddr>   <ver>  <role> <lat> <link>   <lastTX> <lastRX> <path>
272xxxxxxx 1.15.3 LEAF      46 DIRECT   3422     3394     xxx.xxx.253.62/35599
778xxxxxxx -      PLANET    30 DIRECT   3422     7735     xxx.xxx.103.66/9993
cafxxxxxxx -      PLANET    97 DIRECT   3422     8325     xxx.xxx.53.155/9993
cafxxxxxxx -      PLANET    60 DIRECT   3422     8362     xxx.xxx.67.145/9993
cafxxxxxxx -      PLANET   167 DIRECT   3422     7754     xxx.xxx.159.187/9993
  1. Check if networks have been joined successfully
vyos@vyos# run show interfaces zerotier zt1 networks | strip-private
200 listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>
200 listnetworks 272f5xxxxxxxxxxx TestNet xx:xx:xx:xx:xx:01 OK PRIVATE zt1.272f5 xxx.xxx.177.149/16
  1. Optionally, configure a controller-api-key for controller output:
vyos@vyos# show interfaces zerotier zt1 | strip-private
 controller-api-key xxxxxx
 description "test zerotier interface"
 network-id 272f5xxxxxxxxxxx
 primary {
     port 9994
 }
  1. Show peers-detail to show more information for connected peers on the same controller
vyos@vyos# run show interfaces zerotier zt1 peers-detail | strip-private
Name    NodeID      Description          ZeroTier IP    Network           Public IP
------  ----------  -------------------  -------------  ----------------  -------------
R86S    ebaxxxxxxx                       xxx.xxx.100.1   272f5xxxxxxxxxxx  xxx.xxx.209.17
R86S    ebaxxxxxxx  VyOS on R86S Router  xxx.xxx.100.10  60ee7xxxxxxxxxxx  xxx.xxx.209.17
vyos@vyos# run show interfaces zerotier zt1 peers-detail detail | strip-private
 Name        | R86S
 NodeID      | ebaxxxxxxx
 Description |
 ZeroTier IP | xxx.xxx.100.1
 Network     | 272f5xxxxxxxxxxx
 Public IP   | xxx.xxx.209.17
 Last Seen   | 25 Sep 2025 00:30
 Version     | 1.14.2
 Authorized  | True

 Name        | R86S
 NodeID      | ebaxxxxxxx
 Description | VyOS on R86S Router
 ZeroTier IP | xxx.xxx.100.10
 Network     | 60ee7xxxxxxxxxxx
 Public IP   | xxx.xxx.209.17
 Last Seen   | 25 Sep 2025 00:30
 Version     | 1.14.2
 Authorized  | True
  1. Show peers-all to see all peers on the controller:
vyos@vyos# run show interfaces zerotier zt1 peers-all | strip-private
Name         NodeID      Description                ZeroTier IP     Network           Public IP
-----------  ----------  -------------------------  --------------  ----------------  --------------
             7baxxxxxxx                             xxx.xxx.225.56   272f5xxxxxxxxxxx  xxx.xxx.209.17
             cc6xxxxxxx                             xxx.xxx.177.149  272f5xxxxxxxxxxx  xxx.xxx.209.17
             878xxxxxxx                             xxx.xxx.35.119   272f5xxxxxxxxxxx  xxx.xxx.209.17
             878xxxxxxx                             xxx.xxx.100.117  60ee7xxxxxxxxxxx  xxx.xxx.209.17

Smoketest results:

test_basic (__main__.TestInterfacesZerotier.test_basic) ... ok
test_bind (__main__.TestInterfacesZerotier.test_bind) ... ok
test_custom_bonding_policy (__main__.TestInterfacesZerotier.test_custom_bonding_policy) ... ok
test_custom_ports (__main__.TestInterfacesZerotier.test_custom_ports) ... ok
test_generic_local_conf (__main__.TestInterfacesZerotier.test_generic_local_conf) ... ok
test_interface_blacklist (__main__.TestInterfacesZerotier.test_interface_blacklist) ... ok
test_multiple_interfaces (__main__.TestInterfacesZerotier.test_multiple_interfaces) ... ok
test_peer_specific_bonds (__main__.TestInterfacesZerotier.test_peer_specific_bonds) ... ok

Checklist:

  • I have read the CONTRIBUTING document
  • I have linked this PR to one or more Phabricator Task(s)
  • I have run the components SMOKETESTS if applicable
  • My commit headlines contain a valid Task id
  • My change requires a change to the documentation
  • I have updated the documentation accordingly

Copy link

github-actions bot commented Sep 25, 2025

👍
No issues in PR Title / Commit Title

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@sever-sever sever-sever requested a review from Copilot September 25, 2025 10:32
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +155 to +163
string_to_lines = [line for line in json_string.split('\n') if line.strip()]

for line in range(len(string_to_lines) - 1):
# Strip trailing spaces/tabs/newlines before checking
if string_to_lines[line].rstrip().endswith(','):
# If the next line (ignoring indentation) starts with } or ],
# then the comma at the end of this line is invalid → remove it.
if string_to_lines[line + 1].lstrip().startswith(('}', ']')):
string_to_lines[line] = string_to_lines[line].rstrip().rstrip(',')
Copy link

Copilot AI Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function removes empty lines from JSON, which could break formatting of JSON that intentionally includes empty lines. Consider preserving the original line structure and only removing trailing commas without filtering out empty lines.

Suggested change
string_to_lines = [line for line in json_string.split('\n') if line.strip()]
for line in range(len(string_to_lines) - 1):
# Strip trailing spaces/tabs/newlines before checking
if string_to_lines[line].rstrip().endswith(','):
# If the next line (ignoring indentation) starts with } or ],
# then the comma at the end of this line is invalid → remove it.
if string_to_lines[line + 1].lstrip().startswith(('}', ']')):
string_to_lines[line] = string_to_lines[line].rstrip().rstrip(',')
string_to_lines = json_string.split('\n')
for i in range(len(string_to_lines) - 1):
# Only check non-empty lines for trailing commas
if string_to_lines[i].rstrip().endswith(','):
# Find the next non-empty line
j = i + 1
while j < len(string_to_lines) and string_to_lines[j].strip() == '':
j += 1
if j < len(string_to_lines):
# If the next non-empty line (ignoring indentation) starts with } or ],
# then the comma at the end of this line is invalid → remove it.
if string_to_lines[j].lstrip().startswith(('}', ']')):
string_to_lines[i] = string_to_lines[i].rstrip().rstrip(',')

Copilot uses AI. Check for mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty lines in a JSON are about human readability, but the render() pipeline is concerned about machine readable output. There's no benefit to preserving empty lines in this function IMO.

Copy link

CI integration ❌ failed!

Details

CI logs

  • CLI Smoketests (no interfaces) ❌ failed
  • CLI Smoketests VPP ❌ failed
  • CLI Smoketests (interfaces only) 👍 passed
  • Config tests 👍 passed
  • Config tests VPP 👍 passed
  • RAID1 tests 👍 passed
  • TPM tests 👍 passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

1 participant