-
Notifications
You must be signed in to change notification settings - Fork 217
Add IPv6 support in NetworkInterface feature #3957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2274,13 +2274,27 @@ def get_primary_ip_addresses( | |
nic_name = get_matched_str(network_interface.id, NIC_NAME_PATTERN) | ||
nic = network_client.network_interfaces.get(resource_group_name, nic_name) | ||
if nic.primary: | ||
# Check if IPv6 is actually enabled on the NIC | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which setting determines whether IpProtocol.ipv6 is enabled? |
||
# if its enabled, use it as internal ip. | ||
ipv6_enabled = any( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between this value and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is the problem I was having.
Can you suggest a better approach for the above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack, let me rework the PR |
||
ip_config.private_ip_address_version == IpProtocol.ipv6 | ||
for ip_config in nic.ip_configurations | ||
) | ||
if use_ipv6: | ||
nic_index = 1 | ||
|
||
ip_config = nic.ip_configurations[nic_index] | ||
if use_ipv6 and ip_config.private_ip_address_version != IpProtocol.ipv6: | ||
raise LisaException(f"private address is not IPv6 in nic {nic.name}") | ||
private_ip = ip_config.private_ip_address | ||
|
||
# If IPv6 is actually enabled on the NIC, use it as the internal IP. | ||
# Public IP can continue to be IPv4. | ||
if ipv6_enabled: | ||
ipv6_nic_index = 1 | ||
ipv6_config = nic.ip_configurations[ipv6_nic_index] | ||
private_ip = ipv6_config.private_ip_address | ||
else: | ||
private_ip = ip_config.private_ip_address | ||
|
||
if create_public_address: | ||
if not ip_config.public_ip_address: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -783,9 +783,32 @@ class NetworkInterface(AzureFeatureMixin, features.NetworkInterface): | |
def settings_type(cls) -> Type[schema.FeatureSettings]: | ||
return schema.NetworkInterfaceOptionSettings | ||
|
||
@classmethod | ||
def create_setting( | ||
cls, *args: Any, **kwargs: Any | ||
) -> Optional[schema.FeatureSettings]: | ||
# All Azure VMs support synthetic and SRIOV networking | ||
# All Azure VMs can support both IPv4 and IPv6 via ARM template configuration | ||
return schema.NetworkInterfaceOptionSettings( | ||
data_path=search_space.SetSpace( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is this method used? There wasn’t such a method, but the SR-IOV and synthetic settings worked correctly. |
||
items=[ | ||
schema.NetworkDataPath.Synthetic, | ||
schema.NetworkDataPath.Sriov, | ||
] | ||
), | ||
ip_version=search_space.SetSpace( | ||
is_allow_set=True, | ||
items=[ | ||
schema.IPVersion.IPv4, | ||
schema.IPVersion.IPv6, | ||
], | ||
), | ||
) | ||
|
||
def _initialize(self, *args: Any, **kwargs: Any) -> None: | ||
super()._initialize(*args, **kwargs) | ||
self._initialize_information(self._node) | ||
|
||
all_nics = self._get_all_nics() | ||
# store extra synthetic and sriov nics count | ||
# in order to restore nics status after testing which needs change nics | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1199,6 +1199,12 @@ def _create_deployment_parameters( | |
) | ||
arm_parameters.use_ipv6 = self._azure_runbook.use_ipv6 | ||
|
||
# Override IPv6 setting if environment specifically requires IPv6 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The overrides of requirements should be defined in the runbook, and the runbook requirements are merged with the test requirements in |
||
if not arm_parameters.use_ipv6: # Only check if not already enabled | ||
ipv6_required = self._check_ipv6_requirements(environment) | ||
if ipv6_required: | ||
arm_parameters.use_ipv6 = True | ||
|
||
is_windows: bool = False | ||
arm_parameters.admin_username = self.runbook.admin_username | ||
# if no key or password specified, generate the key pair | ||
|
@@ -2242,6 +2248,11 @@ def _generate_max_capability(self, vm_size: str, location: str) -> AzureCapabili | |
](is_allow_set=True, items=[]) | ||
node_space.network_interface.data_path.add(schema.NetworkDataPath.Synthetic) | ||
node_space.network_interface.data_path.add(schema.NetworkDataPath.Sriov) | ||
node_space.network_interface.ip_version = search_space.SetSpace[ | ||
schema.IPVersion | ||
](is_allow_set=True, items=[]) | ||
node_space.network_interface.ip_version.add(schema.IPVersion.IPv4) | ||
node_space.network_interface.ip_version.add(schema.IPVersion.IPv6) | ||
node_space.network_interface.nic_count = search_space.IntRange(min=1) | ||
# till now, the max nic number supported in Azure is 8 | ||
node_space.network_interface.max_nic_count = 8 | ||
|
@@ -3054,6 +3065,29 @@ def _is_byoip_feature_registered(self) -> bool: | |
self._cached_byoip_registered = False | ||
return self._cached_byoip_registered | ||
|
||
def _check_ipv6_requirements(self, environment: Environment) -> bool: | ||
"""Check if IPv6 is specifically required by analyzing environment requirements.""" | ||
ipv6_required = False | ||
|
||
# Check environment runbook node requirements for IPv6 specifications | ||
if environment.runbook and environment.runbook.nodes_requirement: | ||
for node_requirement in environment.runbook.nodes_requirement: | ||
if ( | ||
node_requirement.network_interface | ||
and node_requirement.network_interface.ip_version is not None | ||
): | ||
ip_version = node_requirement.network_interface.ip_version | ||
if isinstance(ip_version, search_space.SetSpace): | ||
if schema.IPVersion.IPv6 in ip_version.items: | ||
ipv6_required = True | ||
break | ||
elif isinstance(ip_version, schema.IPVersion): | ||
if ip_version == schema.IPVersion.IPv6: | ||
ipv6_required = True | ||
break | ||
|
||
return ipv6_required | ||
|
||
|
||
def _get_allowed_locations(nodes_requirement: List[schema.NodeSpace]) -> List[str]: | ||
existing_locations_str: str = "" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ | |
from lisa.tools import Cat | ||
from lisa.tools.start_configuration import StartConfiguration | ||
from lisa.tools.whoami import Whoami | ||
from lisa.util import LisaException, find_patterns_in_lines | ||
from lisa.util import LisaException, find_patterns_in_lines, get_matched_str | ||
|
||
|
||
class IpInfo: | ||
|
@@ -346,6 +346,17 @@ def get_ip_address(self, nic_name: str) -> str: | |
assert "ip_addr" in matched, f"not find ip address for nic {nic_name}" | ||
return matched["ip_addr"] | ||
|
||
def get_ipv6_address(self, nic_name: str) -> str: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a parameter to the |
||
"""Get the global IPv6 address for a network interface.""" | ||
result = self.run(f"-6 addr show {nic_name}", force_run=True, sudo=True) | ||
|
||
# Regex to match IPv6 addresses with global scope | ||
# Example: inet6 2001:db8::5/128 scope global dynamic noprefixroute | ||
ipv6_pattern = re.compile(r"inet6\s+([0-9a-fA-F:]+)\/\d+\s+scope\s+global") | ||
|
||
ipv6_address = get_matched_str(result.stdout, ipv6_pattern) | ||
return ipv6_address | ||
|
||
def get_default_route_info(self) -> tuple[str, str]: | ||
result = self.run("route", force_run=True, sudo=True) | ||
result.assert_exit_code() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it reuse
IpProtocol.ipv6
in other places, instead of creating a new enum?