Skip to content

vyos: Fix handling of IPv6 netmasks on OpenStack#90

Merged
sever-sever merged 1 commit intovyos:currentfrom
jplitza:patch-1
Apr 10, 2026
Merged

vyos: Fix handling of IPv6 netmasks on OpenStack#90
sever-sever merged 1 commit intovyos:currentfrom
jplitza:patch-1

Conversation

@jplitza
Copy link
Copy Markdown
Contributor

@jplitza jplitza commented Mar 25, 2026

Proposed Commit Message

On OpenStack with a network with DHCP disabled, IPv6 routes are passed like this:

    'routes': [{'network': '::', 'netmask': '::', 'gateway': '2001:db8::1'}]

This results in a call to ipaddress.ip_network('::/::'), which Python does not regard as valid network notation.

So this commit uses cloudinit.net.network_state.ipv6_mask_to_net_prefix() to calculate the prefix length from that notation.

Additional Context

Test Steps

Checklist:

  • My code follows the process laid out in the documentation
  • I have updated or added any unit tests accordingly
  • I have updated or added any documentation accordingly

Copy link
Copy Markdown

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

Fixes VyOS network configuration on OpenStack when DHCP is disabled and IPv6 route netmasks are provided in address-form (e.g. ::) instead of a prefix length, which can cause invalid ipaddress.ip_network parsing.

Changes:

  • Added an IPv6 netmask-to-prefix-length conversion helper.
  • Updated v1 subnet route configuration to convert IPv6 netmasks before calling ipaddress.ip_network.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +458 to +462
netmask = ipaddress.ip_address(item['netmask'])
if netmask.version == 6:
netmask = ipaddress_to_prefixlen(netmask)
ip_network = ipaddress.ip_network('{}/{}'.format(
item['network'], item['netmask']))
item['network'], netmask))
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

In route handling, netmask = ipaddress.ip_address(item['netmask']) will break when item['netmask'] is an integer prefix length (e.g. 64) or a prefix string (e.g. '64'): ip_address(64) becomes an IPv4 address and '64' raises ValueError, leading to invalid ip_network('{}/{}'.format(item['network'], netmask)). Consider passing through prefix lengths unchanged and only converting when the netmask is an IPv6 address-form string (like '::'/'ffff:...'), or use the existing cloudinit.net.network_state.ipv6_mask_to_net_prefix helper which already supports both prefix and IPv6-netmask inputs.

Copilot uses AI. Check for mistakes.
Comment on lines +133 to +146
# Python's ipaddress.ip_network does not support something like ::/:: as
# input. So we have to convert the IPv6 address notation of the netmask
# to the integer prefix length.
def ipaddress_to_prefixlen(addr):
prefixlen = addr.max_prefixlen
register = int(addr)
if register == 0:
return 0
while not register & 1:
prefixlen -= 1
register = register >> 1
if register != 2**prefixlen - 1:
raise ValueError("{} does not appear to be a netmask".format(addr))
return prefixlen
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

This PR adds ipaddress_to_prefixlen, but cloud-init already provides ipv6_mask_to_net_prefix in cloudinit.net.network_state, which handles both prefix-length strings (e.g. '64') and IPv6 netmask notation (e.g. 'ffff:ffff:ffff::') and validates contiguity. Reusing the shared helper would reduce duplicated logic and keep netmask parsing consistent across the codebase.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 26, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@jplitza
Copy link
Copy Markdown
Contributor Author

jplitza commented Mar 26, 2026

I have read the CLA Document and I hereby sign the CLA

vyosbot added a commit to vyos/vyos-cla-signatures that referenced this pull request Mar 26, 2026
Copy link
Copy Markdown
Contributor

@zdc zdc left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

  1. The Cloud-init specification is clear about requiring a netmask to be noted in CIDR for IPv6. So, the original issue is in OpenStack.
  2. However, even inside Cloud-init sources, we see usage of ipv6_mask_to_net_prefix() specifically to cover this issue with OpenStack.
  3. Therefore, it makes sense to adopt the same workaround for our module.

The PR is good and will be approved, but please squash all commits into a single one before we do this.


I think it makes sense to file the bug report in OpenStack as well. This is not the first time we have seen non-following specs on various platforms, and trying to cover everything with workarounds will be hard in the long run.

On OpenStack with a network with DHCP disabled, IPv6 routes are passed
like this:

    'routes': [{'network': '::', 'netmask': '::', 'gateway': '2001:db8::1'}]

This results in a call to ipaddress.ip_network('::/::'), which Python
does not regard as valid network notation.

So this commit uses ipv6_mask_to_net_prefix from the package
cloudinit.net.network_state to convert the netmask for IPv6 networks.
Copy link
Copy Markdown
Contributor

@zdc zdc left a comment

Choose a reason for hiding this comment

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

It is good now. Thanks @jplitza !

Copy link
Copy Markdown
Member

@sever-sever sever-sever left a comment

Choose a reason for hiding this comment

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

Fix Openstack IPv6 netmasks

@sever-sever sever-sever merged commit 57f8b20 into vyos:current Apr 10, 2026
1 check passed
@vyosbot vyosbot added mirror-initiated This PR initiated for mirror sync workflow mirror-completed This PR has been mirrored successfully and removed mirror-initiated This PR initiated for mirror sync workflow labels Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mirror-completed This PR has been mirrored successfully

Development

Successfully merging this pull request may close these issues.

5 participants