Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions perfkitbenchmarker/linux_benchmarks/iperf_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
IPERF_UDP_PORT = 25000
IPERF_RETRIES = 5

IPERF_PORT_IPV6 = IPERF_PORT + 1
IPERF_UDP_PORT_IPV6 = IPERF_UDP_PORT + 1


def GetConfig(user_config):
return configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME)
Expand Down Expand Up @@ -145,6 +148,12 @@ def Prepare(benchmark_spec):
if UDP in FLAGS.iperf_benchmarks:
vm.AllowPort(IPERF_UDP_PORT)

if vm_util.ShouldRunOnExternalIpv6Address(vm):
if TCP in FLAGS.iperf_benchmarks:
vm.AllowPort(IPERF_PORT_IPV6, source_range = ['::/0'])
if UDP in FLAGS.iperf_benchmarks:
vm.AllowPort(IPERF_UDP_PORT_IPV6, source_range = ['::/0'])

if TCP in FLAGS.iperf_benchmarks:
stdout, _ = vm.RemoteCommand(
f'nohup iperf --server --port {IPERF_PORT} &> /dev/null & echo $!'
Expand All @@ -154,6 +163,17 @@ def Prepare(benchmark_spec):
vm.iperf_tcp_server_pid = stdout.strip()
# Check that the server is actually running
vm.RemoteCommand(f'ps -p {vm.iperf_tcp_server_pid}')

if vm_util.ShouldRunOnExternalIpv6Address(vm):
stdout, _ = vm.RemoteCommand(
f'nohup iperf -V --server --port {IPERF_PORT_IPV6} &> /dev/null & echo $!'
)

# TODO(user): store this in a better place
vm.iperf_tcp_server_pid_ipv6 = stdout.strip()
# Check that the server is actually running
vm.RemoteCommand(f'ps -p {vm.iperf_tcp_server_pid_ipv6}')

if UDP in FLAGS.iperf_benchmarks:
stdout, _ = vm.RemoteCommand(
f'nohup iperf --server --bind {vm.internal_ip} --udp '
Expand All @@ -164,6 +184,16 @@ def Prepare(benchmark_spec):
# Check that the server is actually running
vm.RemoteCommand(f'ps -p {vm.iperf_udp_server_pid}')

if vm_util.ShouldRunOnExternalIpv6Address(vm):
stdout, _ = vm.RemoteCommand(
f'nohup iperf -V --server --bind {vm.ipv6_address} --udp '
f'--port {IPERF_UDP_PORT_IPV6} &> /dev/null & echo $!'
)
# TODO(user): store this in a better place
vm.iperf_udp_server_pid_ipv6 = stdout.strip()
# Check that the server is actually running
vm.RemoteCommand(f'ps -p {vm.iperf_udp_server_pid_ipv6}')


@vm_util.Retry(max_retries=IPERF_RETRIES)
def _RunIperf(
Expand All @@ -174,6 +204,7 @@ def _RunIperf(
ip_type,
protocol,
interval_size=None,
using_ipv6 = False,
):
"""Run iperf using sending 'vm' to connect to 'ip_address'.

Expand All @@ -185,6 +216,7 @@ def _RunIperf(
ip_type: The IP type of 'ip_address' (e.g. 'internal', 'external')
protocol: The protocol for Iperf to use. Either 'TCP' or 'UDP'
interval_size: Time interval at which to output stats.
using_ipv6: Whether receiving_ip_address is IPv6 or not

Returns:
A Sample.
Expand All @@ -199,6 +231,7 @@ def _RunIperf(
'sending_zone': sending_vm.zone,
'runtime_in_seconds': FLAGS.iperf_runtime_in_seconds,
'ip_type': ip_type,
'using_ipv6': using_ipv6,
}

if protocol == TCP:
Expand All @@ -208,6 +241,13 @@ def _RunIperf(
f'--parallel {thread_count}'
)

if using_ipv6:
iperf_cmd = (
f'iperf -V --enhancedreports --client {receiving_ip_address} --port '
f'{IPERF_PORT_IPV6} --format m --time {FLAGS.iperf_runtime_in_seconds} '
f'--parallel {thread_count}'
)

if FLAGS.iperf_interval:
iperf_cmd += f' --interval {FLAGS.iperf_interval}'

Expand Down Expand Up @@ -437,6 +477,13 @@ def _RunIperf(
f' {IPERF_UDP_PORT} --format m --time {FLAGS.iperf_runtime_in_seconds}'
f' --parallel {thread_count} '
)

if using_ipv6:
iperf_cmd = (
f'iperf -V --enhancedreports --udp --client {receiving_ip_address} --port'
f' {IPERF_UDP_PORT_IPV6} --format m --time {FLAGS.iperf_runtime_in_seconds}'
f' --parallel {thread_count} '
)

if FLAGS.iperf_udp_per_stream_bandwidth:
iperf_cmd += f' --bandwidth {FLAGS.iperf_udp_per_stream_bandwidth}M'
Expand Down Expand Up @@ -603,6 +650,22 @@ def Run(benchmark_spec):

time.sleep(FLAGS.iperf_sleep_time)

# Send using external IPv6 addresses
if vm_util.ShouldRunOnExternalIpv6Address(receiving_vm):
results.append(
_RunIperf(
sending_vm,
receiving_vm,
receiving_vm.ipv6_address,
thread_count,
vm_util.IpAddressMetadata.EXTERNAL,
protocol,
interval_size=FLAGS.iperf_interval,
using_ipv6 = True,
)
)
time.sleep(FLAGS.iperf_sleep_time)

return results


Expand All @@ -619,7 +682,18 @@ def Cleanup(benchmark_spec):
vm.RemoteCommand(
f'kill -9 {vm.iperf_tcp_server_pid}', ignore_failure=True
)

if vm_util.ShouldRunOnExternalIpv6Address(vm):
vm.RemoteCommand(
f'kill -9 {vm.iperf_tcp_server_pid_ipv6}', ignore_failure=True
)

if UDP in FLAGS.iperf_benchmarks:
vm.RemoteCommand(
f'kill -9 {vm.iperf_udp_server_pid}', ignore_failure=True
)

if vm_util.ShouldRunOnExternalIpv6Address(vm):
vm.RemoteCommand(
f'kill -9 {vm.iperf_udp_server_pid_ipv6}', ignore_failure=True
)
22 changes: 22 additions & 0 deletions perfkitbenchmarker/linux_benchmarks/netperf_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ def PrepareServerVM(server_vm, client_vm_internal_ips, client_vm_ip_address):
if vm_util.ShouldRunOnExternalIpAddress():
# Open all of the command and data ports
server_vm.AllowPort(PORT_START, PORT_START + num_streams * 2 - 1)

if vm_util.ShouldRunOnExternalIpv6Address(server_vm):
server_vm.AllowPort(PORT_START, PORT_START + num_streams * 2 - 1, ['::/0'])

port_end = PORT_START + num_streams * 2 - 1
netserver_cmd = (
Expand Down Expand Up @@ -773,6 +776,7 @@ def RunClientServerVMs(client_vm, server_vm):
external_ip_result.metadata['ip_type'] = (
vm_util.IpAddressMetadata.EXTERNAL
)
external_ip_result.metadata['using_ipv6'] = (False)
external_ip_result.metadata.update(metadata)
results.extend(external_ip_results)

Expand All @@ -789,8 +793,26 @@ def RunClientServerVMs(client_vm, server_vm):
internal_ip_result.metadata['ip_type'] = (
vm_util.IpAddressMetadata.INTERNAL
)
internal_ip_result.metadata['using_ipv6'] = (False)
results.extend(internal_ip_results)

if vm_util.ShouldRunOnExternalIpv6Address(server_vm) and vm_util.ShouldRunOnExternalIpv6Address(client_vm):
external_ipv6_results = RunNetperf(
client_vm,
netperf_benchmark,
[server_vm.ipv6_address],
num_streams,
# NAT translates internal to external IP when remote IP is external
[client_vm.ipv6_address],
)
for external_ipv6_result in external_ipv6_results:
external_ipv6_result.metadata['ip_type'] = (
vm_util.IpAddressMetadata.EXTERNAL
)
external_ipv6_result.metadata['using_ipv6'] = (True)
external_ipv6_result.metadata.update(metadata)
results.extend(external_ipv6_results)

return results


Expand Down
13 changes: 12 additions & 1 deletion perfkitbenchmarker/linux_benchmarks/ping_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ def Prepare(benchmark_spec): # pylint: disable=unused-argument
vms = benchmark_spec.vms
for vm in vms:
vm.AllowIcmp()
vms = benchmark_spec.vms
for vm in vms:
if vm_util.ShouldRunOnExternalIpv6Address(vm):
vm.AllowIcmpIpv6()


def Run(benchmark_spec):
Expand All @@ -88,10 +92,15 @@ def Run(benchmark_spec):
results = results + _RunPing(
sending_vm, receiving_vm, receiving_vm.internal_ip, ip_type
)
if vm_util.ShouldRunOnExternalIpv6Address(receiving_vm):
ip_type = vm_util.IpAddressMetadata.EXTERNAL
results = results + _RunPing(
sending_vm, receiving_vm, receiving_vm.ipv6_address, ip_type, using_ipv6=True
)
return results


def _RunPing(sending_vm, receiving_vm, receiving_ip, ip_type):
def _RunPing(sending_vm, receiving_vm, receiving_ip, ip_type, using_ipv6 = False):
"""Run ping using 'sending_vm' to connect to 'receiving_ip'.

Args:
Expand All @@ -100,6 +109,7 @@ def _RunPing(sending_vm, receiving_vm, receiving_ip, ip_type):
receiving_ip: The IP address to be pinged.
ip_type: The type of 'receiving_ip', (either
'vm_util.IpAddressSubset.INTERNAL or vm_util.IpAddressSubset.EXTERNAL')
using_ipv6: True if receiving_ip is IPv6, False if not

Returns:
A list of samples, with one sample for each metric.
Expand All @@ -120,6 +130,7 @@ def _RunPing(sending_vm, receiving_vm, receiving_ip, ip_type):

metadata = {
'ip_type': ip_type,
'using_ipv6': using_ipv6,
'receiving_zone': receiving_vm.zone,
'sending_zone': sending_vm.zone,
}
Expand Down
8 changes: 8 additions & 0 deletions perfkitbenchmarker/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ def AllowIcmp(self, vm):
"""
pass

def AllowIcmpIpv6(self, vm):
"""Opens the ICMP for IPv6 protocol on the firewall

Args:
vm: The BaseVirtualMachine object to open the ICMP for IPv6 protocol for.
"""
pass

def AllowPort(
self,
vm,
Expand Down
38 changes: 38 additions & 0 deletions perfkitbenchmarker/providers/gcp/gce_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,13 +692,17 @@ def AllowPort(
start_port,
end_port,
)
if source_range is not None:
firewall_name += f'-{source_range.replace(':','c').replace('/','s')}'
key = (vm.project, vm.cidr, start_port, end_port, source_range)
else:
firewall_name = 'perfkit-firewall-%s-%d-%d' % (
FLAGS.run_uri,
start_port,
end_port,
)
if source_range is not None:
firewall_name += f'-{source_range.replace(':','c').replace('/','s')}'
key = (vm.project, start_port, end_port, source_range)
if key in self.firewall_rules:
return
Expand Down Expand Up @@ -753,6 +757,37 @@ def AllowIcmp(self, vm):
self.firewall_icmp_rules[key] = firewall_rule
firewall_rule.Create()

def AllowIcmpIpv6(self, vm):
"""Open the ICMP for IPv6 protocl on the firewall.
Note: Protocol Number for ICMP for IPv6 is 58.
(https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml)

Args:
vm: The BaseVirtualMachine object to open the ICMP for IPv6 protocol for.
"""
if vm.is_static:
return
with self._lock:
if vm.cidr:
cidr_string = network.BaseNetwork.FormatCidrString(vm.cidr)
firewall_name = 'perfkit-firewall-icmp-ipv6-%s-%s' % (
cidr_string,
FLAGS.run_uri,
)
key = (vm.project, vm.cidr, 'ipv6')
else:
firewall_name = 'perfkit-firewall-icmp-ipv6-%s' % FLAGS.run_uri
key = (vm.project, 'ipv6')

if key in self.firewall_icmp_rules:
return

allow = '58' # ICMP for IPv6 Protocol Number
firewall_rule = GceFirewallRule(
firewall_name, vm.project, allow, vm.network.network_resource.name, "::/0"
)
self.firewall_icmp_rules[key] = firewall_rule
firewall_rule.Create()

class GceNetworkSpec(network.BaseNetworkSpec):
"""Object representing a GCE Network specification."""
Expand Down Expand Up @@ -873,6 +908,9 @@ def _Create(self):
cmd.flags['network'] = self.network_name
cmd.flags['region'] = self.region
cmd.flags['range'] = self.addr_range
if FLAGS.assign_external_ipv6:
cmd.flags['stack-type'] = 'IPV4_IPV6'
cmd.flags['ipv6-access-type'] = 'EXTERNAL'
cmd.Issue()

def _Exists(self) -> bool:
Expand Down
8 changes: 8 additions & 0 deletions perfkitbenchmarker/providers/gcp/gce_virtual_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,9 @@ def _GenerateCreateCommand(self, ssh_keys_path):
no_address_arg = []
if not self.assign_external_ip or idx > 0:
no_address_arg = ['no-address']
ipv6_args = []
if self.assign_external_ipv6:
ipv6_args = ['stack-type=IPV4_IPV6', 'ipv6-network-tier=PREMIUM']
cmd.additional_flags += [
'--network-interface',
','.join(
Expand All @@ -744,6 +747,7 @@ def _GenerateCreateCommand(self, ssh_keys_path):
]
+ gce_nic_queue_count_arg
+ no_address_arg
+ ipv6_args
),
]

Expand Down Expand Up @@ -1106,6 +1110,9 @@ def _ParseDescribeResponse(self, describe_response):

for network_interface in describe_response['networkInterfaces']:
self.internal_ips.append(network_interface['networkIP'])

if 'ipv6AccessConfigs' in network_interface:
self.ipv6_address = network_interface['ipv6AccessConfigs'][0]['externalIpv6']

@property
def HasIpAddress(self):
Expand All @@ -1118,6 +1125,7 @@ def _NeedsToParseDescribeResponse(self):
not self.id
or not self.GetInternalIPs()
or (self.assign_external_ip and not self.ip_address)
or (self.assign_external_ipv6 and not self.ipv6_address)
)

@vm_util.Retry()
Expand Down
Loading