Skip to content

Commit

Permalink
Check the validity of management IP addresses (#1965)
Browse files Browse the repository at this point in the history
clab and libvirt management IP addresses must be within the management
subnet and the AF used on the node must be defined in the management
pool.

Furthermore, libvirt nodes need IPv4 management address.

Closes #1957
  • Loading branch information
ipspace authored Feb 22, 2025
1 parent b37dc65 commit 44c198d
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 6 deletions.
4 changes: 2 additions & 2 deletions netsim/augment/addressing.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ def validate_pools(addrs: Box, topology: Box) -> None:
module='addressing')

if 'ipv6' in pfx and 'ipv6_pfx' in pfx:
if pfx.ipv6_pfx.prefixlen > 56:
if pfx.ipv6_pfx.prefixlen > 56 and pool != 'mgmt':
log.error(
"Error in '%s' addressing pool: IPv6 pool prefix cannot be longer than /56" % pool,
f"Error in '{pool}' addressing pool: IPv6 pool prefix cannot be longer than /56",
category=log.IncorrectValue,
module='addressing')

Expand Down
40 changes: 39 additions & 1 deletion netsim/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import os
import typing
import pathlib
import ipaddress

# Related modules
from box import Box
Expand Down Expand Up @@ -378,11 +379,48 @@ def get_forwarded_ports(node: Box, topology: Box) -> list:
"""
validate_images -- check the images used by individual nodes against provider image repo
"""

def validate_images(topology: Box) -> None:
p_cache: dict = {}

for n_data in topology.nodes.values():
execute_node('validate_node_image',n_data,topology)

log.exit_on_error()

"""
validate_mgmt_ip -- Validate management IP addresses
"""
def validate_mgmt_ip(
node: Box,
provider: str,
mgmt: Box,
required: bool = False,
v4only: bool = False) -> None:

valid_af = ['ipv4'] if v4only else ['ipv4','ipv6']
n_mgmt = node.mgmt
node_af = [ n_af for n_af in n_mgmt.keys() if n_af in valid_af ]
if not node_af and required:
log.error(
f'Node {node.name} must have {" or ".join(valid_af)} management address',
category=log.MissingValue,
module=provider)

if not mgmt:
return

for af in ['ipv4','ipv6']:
if af not in n_mgmt:
continue
m_addr = ipaddress.ip_interface(n_mgmt[af])
pfx = mgmt.get(f'{af}_pfx',None)
if pfx is None:
log.error(
f'Node {node.name} has an {af} management address, but the mgmt pool does not have an {af} prefix',
category=log.IncorrectValue,
module=provider)
elif not m_addr.network.subnet_of(pfx):
log.error(
f'Management {af} address of node {node.name} ({n_mgmt[af]}) is not part of the management subnet',
category=log.IncorrectValue,
module=provider)
3 changes: 2 additions & 1 deletion netsim/providers/clab.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pathlib
import argparse

from . import _Provider,get_forwarded_ports
from . import _Provider,get_forwarded_ports,validate_mgmt_ip
from ..utils import log, strings, linuxbridge
from ..data import filemaps, get_empty_box, append_to_list
from ..data.types import must_be_dict
Expand Down Expand Up @@ -183,6 +183,7 @@ def augment_node_data(self, node: Box, topology: Box) -> None:
def node_post_transform(self, node: Box, topology: Box) -> None:
add_daemon_filemaps(node,topology)
normalize_clab_filemaps(node)
validate_mgmt_ip(node,required=True,provider='clab',mgmt=topology.addressing.mgmt)

self.create_extra_files_mappings(node,topology)

Expand Down
5 changes: 3 additions & 2 deletions netsim/providers/libvirt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from ..data import types,get_empty_box,get_box
from ..utils import log,strings,linuxbridge
from ..utils import files as _files
from . import _Provider
from . import _Provider,validate_mgmt_ip
from ..augment import devices
from ..augment.links import get_link_by_index
from ..cli import is_dry_run,external_commands
Expand Down Expand Up @@ -263,7 +263,7 @@ def create_vagrant_batches(topology: Box) -> None:
class Libvirt(_Provider):

"""
post_transform hook: mark multi-provider links as LAN links
pre_transform hook: mark multi-provider links as LAN links
"""
def pre_transform(self, topology: Box) -> None:
if not 'links' in topology:
Expand Down Expand Up @@ -295,6 +295,7 @@ def pre_transform(self, topology: Box) -> None:
def node_post_transform(self, node: Box, topology: Box) -> None:
if node.get('_set_ifindex'):
pad_node_interfaces(node,topology)
validate_mgmt_ip(node,required=True,v4only=True,provider='libvirt',mgmt=topology.addressing.mgmt)

def transform_node_images(self, topology: Box) -> None:
self.node_image_version(topology)
Expand Down
4 changes: 4 additions & 0 deletions tests/errors/mgmt-subnet.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
IncorrectValue in libvirt: Management ipv4 address of node a (192.168.44.1) is not part of the management subnet
MissingValue in libvirt: Node b must have ipv4 management address
IncorrectValue in clab: Management ipv6 address of node d (2001:db8:43::3) is not part of the management subnet
Fatal error in netlab: Cannot proceed beyond this point due to errors, exiting
22 changes: 22 additions & 0 deletions tests/errors/mgmt-subnet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defaults.device: none
addressing.mgmt:
ipv4: 192.168.42.0/24
ipv6: 2001:db8:42::/64

nodes:
a:
provider: libvirt
mgmt.ipv4: 192.168.44.1
b:
provider: libvirt
mgmt.ipv6: 2001:db8:42::2
c:
provider: libvirt
mgmt.ipv4: 192.168.42.3
mgmt.ipv6: 2001:db8:42::3
d:
provider: clab
mgmt.ipv6: 2001:db8:43::3
e:
provider: clab
mgmt.ipv6: 2001:db8:42::5

0 comments on commit 44c198d

Please sign in to comment.