1# SPDX-License-Identifier: GPL-2.0 2# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 4# Test various network-related functionality, such as the dhcp, ping, and 5# tftpboot commands. 6 7""" 8Note: This test relies on boardenv_* containing configuration values to define 9which network environment is available for testing. Without this, this test 10will be automatically skipped. 11 12For example: 13 14.. code-block:: python 15 16 # Boolean indicating whether the Ethernet device is attached to USB, and hence 17 # USB enumeration needs to be performed prior to network tests. 18 # This variable may be omitted if its value is False. 19 env__net_uses_usb = False 20 21 # Boolean indicating whether the Ethernet device is attached to PCI, and hence 22 # PCI enumeration needs to be performed prior to network tests. 23 # This variable may be omitted if its value is False. 24 env__net_uses_pci = True 25 26 # True if a DHCP server is attached to the network, and should be tested. 27 # If DHCP testing is not possible or desired, this variable may be omitted or 28 # set to False. 29 env__net_dhcp_server = True 30 31 # False or omitted if a DHCP server is attached to the network, and dhcp abort 32 # case should be tested. 33 # If DHCP abort testing is not possible or desired, set this variable to True. 34 # For example: On some setup, dhcp is too fast and this case may not work. 35 env__dhcp_abort_test_skip = True 36 37 # True if a DHCPv6 server is attached to the network, and should be tested. 38 # If DHCPv6 testing is not possible or desired, this variable may be omitted or 39 # set to False. 40 env__net_dhcp6_server = True 41 42 # A list of environment variables that should be set in order to configure a 43 # static IP. If solely relying on DHCP, this variable may be omitted or set to 44 # an empty list. 45 env__net_static_env_vars = [ 46 ('ipaddr', '10.0.0.100'), 47 ('netmask', '255.255.255.0'), 48 ('serverip', '10.0.0.1'), 49 ] 50 51 # Details regarding a file that may be read from a TFTP server. This variable 52 # may be omitted or set to None if TFTP testing is not possible or desired. 53 env__net_tftp_readable_file = { 54 'fn': 'ubtest-readable.bin', 55 'addr': 0x10000000, 56 'size': 5058624, 57 'crc32': 'c2244b26', 58 'timeout': 50000, 59 'fnu': 'ubtest-upload.bin', 60 } 61 62 # Details regarding a file that may be read from a NFS server. This variable 63 # may be omitted or set to None if NFS testing is not possible or desired. 64 env__net_nfs_readable_file = { 65 'fn': 'ubtest-readable.bin', 66 'addr': 0x10000000, 67 'size': 5058624, 68 'crc32': 'c2244b26', 69 } 70 71 # Details regarding a file that may be read from a TFTP server. This variable 72 # may be omitted or set to None if PXE testing is not possible or desired. 73 env__net_pxe_readable_file = { 74 'fn': 'default', 75 'addr': 0x2000000, 76 'size': 74, 77 'timeout': 50000, 78 'pattern': 'Linux', 79 } 80 81 # True if a router advertisement service is connected to the network, and should 82 # be tested. If router advertisement testing is not possible or desired, this 83 variable may be omitted or set to False. 84 env__router_on_net = True 85""" 86 87import pytest 88import utils 89import uuid 90import datetime 91import re 92 93net_set_up = False 94net6_set_up = False 95 96 97@pytest.mark.buildconfigspec('cmd_net') 98def test_net_pre_commands(ubman): 99 """Execute any commands required to enable network hardware. 100 101 These commands are provided by the boardenv_* file; see the comment at the 102 beginning of this file. 103 """ 104 105 init_usb = ubman.config.env.get('env__net_uses_usb', False) 106 if init_usb: 107 ubman.run_command('usb start') 108 109 init_pci = ubman.config.env.get('env__net_uses_pci', False) 110 if init_pci: 111 ubman.run_command('pci enum') 112 113 ubman.run_command('net list') 114 115@pytest.mark.buildconfigspec('cmd_dhcp') 116def test_net_dhcp(ubman): 117 """Test the dhcp command. 118 119 The boardenv_* file may be used to enable/disable this test; see the 120 comment at the beginning of this file. 121 """ 122 123 test_dhcp = ubman.config.env.get('env__net_dhcp_server', False) 124 if not test_dhcp: 125 pytest.skip('No DHCP server available') 126 127 ubman.run_command('setenv autoload no') 128 output = ubman.run_command('dhcp') 129 assert 'DHCP client bound to address ' in output 130 131 global net_set_up 132 net_set_up = True 133 134@pytest.mark.buildconfigspec('cmd_dhcp') 135@pytest.mark.buildconfigspec('cmd_mii') 136def test_net_dhcp_abort(ubman): 137 """Test the dhcp command by pressing ctrl+c in the middle of dhcp request 138 139 The boardenv_* file may be used to enable/disable this test; see the 140 comment at the beginning of this file. 141 """ 142 143 test_dhcp = ubman.config.env.get('env__net_dhcp_server', False) 144 if not test_dhcp: 145 pytest.skip('No DHCP server available') 146 147 if ubman.config.env.get('env__dhcp_abort_test_skip', True): 148 pytest.skip('DHCP abort test is not enabled!') 149 150 ubman.run_command('setenv autoload no') 151 152 # Phy reset before running dhcp command 153 output = ubman.run_command('mii device') 154 if not re.search(r"Current device: '(.+?)'", output): 155 pytest.skip('PHY device does not exist!') 156 eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0] 157 ubman.run_command(f'mii device {eth_num}') 158 output = ubman.run_command('mii info') 159 eth_addr = hex(int(re.search(r'PHY (.+?):', output).groups()[0], 16)) 160 ubman.run_command(f'mii modify {eth_addr} 0 0x8000 0x8000') 161 162 ubman.run_command('dhcp', wait_for_prompt=False) 163 try: 164 ubman.wait_for('Waiting for PHY auto negotiation to complete') 165 except: 166 pytest.skip('Timeout waiting for PHY auto negotiation to complete') 167 168 ubman.wait_for('done') 169 170 try: 171 # Sending Ctrl-C 172 output = ubman.run_command( 173 chr(3), wait_for_echo=False, send_nl=False 174 ) 175 assert 'TIMEOUT' not in output 176 assert 'DHCP client bound to address ' not in output 177 assert 'Abort' in output 178 finally: 179 # Provide a time to recover from Abort - if it is not performed 180 # There is message like: ethernet@ff0e0000: No link. 181 ubman.run_command('sleep 1') 182 # Run the dhcp test to setup the network configuration 183 test_net_dhcp(ubman) 184 185@pytest.mark.buildconfigspec('cmd_dhcp6') 186def test_net_dhcp6(ubman): 187 """Test the dhcp6 command. 188 189 The boardenv_* file may be used to enable/disable this test; see the 190 comment at the beginning of this file. 191 """ 192 193 test_dhcp6 = ubman.config.env.get('env__net_dhcp6_server', False) 194 if not test_dhcp6: 195 pytest.skip('No DHCP6 server available') 196 197 ubman.run_command('setenv autoload no') 198 output = ubman.run_command('dhcp6') 199 assert 'DHCP6 client bound to ' in output 200 201 global net6_set_up 202 net6_set_up = True 203 204@pytest.mark.buildconfigspec('net', 'net_lwip') 205def test_net_setup_static(ubman): 206 """Set up a static IP configuration. 207 208 The configuration is provided by the boardenv_* file; see the comment at 209 the beginning of this file. 210 """ 211 212 env_vars = ubman.config.env.get('env__net_static_env_vars', None) 213 if not env_vars: 214 pytest.skip('No static network configuration is defined') 215 216 for (var, val) in env_vars: 217 ubman.run_command('setenv %s %s' % (var, val)) 218 219 global net_set_up 220 net_set_up = True 221 222@pytest.mark.buildconfigspec('cmd_ping') 223def test_net_ping(ubman): 224 """Test the ping command. 225 226 The $serverip (as set up by either test_net_dhcp or test_net_setup_static) 227 is pinged. The test validates that the host is alive, as reported by the 228 ping command's output. 229 """ 230 231 if not net_set_up: 232 pytest.skip('Network not initialized') 233 234 output = ubman.run_command('ping $serverip') 235 assert 'is alive' in output 236 237@pytest.mark.buildconfigspec('IPV6_ROUTER_DISCOVERY') 238def test_net_network_discovery(ubman): 239 """Test the network discovery feature of IPv6. 240 241 An IPv6 network command (ping6 in this case) is run to make U-Boot send a 242 router solicitation packet, receive a router advertisement message, and 243 parse it. 244 A router advertisement service needs to be running for this test to succeed. 245 U-Boot receives the RA, processes it, and if successful, assigns the gateway 246 IP and prefix length. 247 The configuration is provided by the boardenv_* file; see the comment at 248 the beginning of this file. 249 """ 250 251 router_on_net = ubman.config.env.get('env__router_on_net', False) 252 if not router_on_net: 253 pytest.skip('No router on network') 254 255 fake_host_ip = 'fe80::215:5dff:fef6:2ec6' 256 output = ubman.run_command('ping6 ' + fake_host_ip) 257 assert 'ROUTER SOLICITATION 1' in output 258 assert 'Set gatewayip6:' in output 259 assert '0000:0000:0000:0000:0000:0000:0000:0000' not in output 260 261@pytest.mark.buildconfigspec('cmd_tftpboot') 262def test_net_tftpboot(ubman): 263 """Test the tftpboot command. 264 265 A file is downloaded from the TFTP server, its size and optionally its 266 CRC32 are validated. 267 268 The details of the file to download are provided by the boardenv_* file; 269 see the comment at the beginning of this file. 270 """ 271 272 if not net_set_up: 273 pytest.skip('Network not initialized') 274 275 f = ubman.config.env.get('env__net_tftp_readable_file', None) 276 if not f: 277 pytest.skip('No TFTP readable file to read') 278 279 addr = f.get('addr', None) 280 281 fn = f['fn'] 282 if not addr: 283 output = ubman.run_command('tftpboot %s' % (fn)) 284 else: 285 output = ubman.run_command('tftpboot %x %s' % (addr, fn)) 286 expected_text = 'Bytes transferred = ' 287 sz = f.get('size', None) 288 if sz: 289 expected_text += '%d' % sz 290 assert expected_text in output 291 292 expected_crc = f.get('crc32', None) 293 if not expected_crc: 294 return 295 296 if ubman.config.buildconfig.get('config_cmd_crc32', 'n') != 'y': 297 return 298 299 output = ubman.run_command('crc32 $fileaddr $filesize') 300 assert expected_crc in output 301 302@pytest.mark.buildconfigspec('cmd_nfs') 303def test_net_nfs(ubman): 304 """Test the nfs command. 305 306 A file is downloaded from the NFS server, its size and optionally its 307 CRC32 are validated. 308 309 The details of the file to download are provided by the boardenv_* file; 310 see the comment at the beginning of this file. 311 """ 312 313 if not net_set_up: 314 pytest.skip('Network not initialized') 315 316 f = ubman.config.env.get('env__net_nfs_readable_file', None) 317 if not f: 318 pytest.skip('No NFS readable file to read') 319 320 addr = f.get('addr', None) 321 if not addr: 322 addr = utils.find_ram_base(ubman) 323 324 fn = f['fn'] 325 output = ubman.run_command('nfs %x %s' % (addr, fn)) 326 expected_text = 'Bytes transferred = ' 327 sz = f.get('size', None) 328 if sz: 329 expected_text += '%d' % sz 330 assert expected_text in output 331 332 expected_crc = f.get('crc32', None) 333 if not expected_crc: 334 return 335 336 if ubman.config.buildconfig.get('config_cmd_crc32', 'n') != 'y': 337 return 338 339 output = ubman.run_command('crc32 %x $filesize' % addr) 340 assert expected_crc in output 341 342@pytest.mark.buildconfigspec("cmd_pxe") 343def test_net_pxe_get(ubman): 344 """Test the pxe get command. 345 346 A pxe configuration file is downloaded from the TFTP server and interpreted 347 to boot the images mentioned in pxe configuration file. 348 349 The details of the file to download are provided by the boardenv_* file; 350 see the comment at the beginning of this file. 351 """ 352 353 if not net_set_up: 354 pytest.skip("Network not initialized") 355 356 test_net_setup_static(ubman) 357 358 f = ubman.config.env.get("env__net_pxe_readable_file", None) 359 if not f: 360 pytest.skip("No PXE readable file to read") 361 362 addr = f.get("addr", None) 363 timeout = f.get("timeout", ubman.p.timeout) 364 365 pxeuuid = uuid.uuid1() 366 ubman.run_command(f"setenv pxeuuid {pxeuuid}") 367 expected_text_uuid = f"Retrieving file: pxelinux.cfg/{pxeuuid}" 368 369 ethaddr = ubman.run_command("echo $ethaddr") 370 ethaddr = ethaddr.replace(':', '-') 371 expected_text_ethaddr = f"Retrieving file: pxelinux.cfg/01-{ethaddr}" 372 373 ip = ubman.run_command("echo $ipaddr") 374 ip = ip.split('.') 375 ipaddr_file = "".join(['%02x' % int(x) for x in ip]).upper() 376 expected_text_ipaddr = f"Retrieving file: pxelinux.cfg/{ipaddr_file}" 377 expected_text_default = f"Retrieving file: pxelinux.cfg/default" 378 379 with ubman.temporary_timeout(timeout): 380 output = ubman.run_command("pxe get") 381 382 assert "TIMEOUT" not in output 383 assert expected_text_uuid in output 384 assert expected_text_ethaddr in output 385 assert expected_text_ipaddr in output 386 387 i = 1 388 for i in range(0, len(ipaddr_file) - 1): 389 expected_text_ip = f"Retrieving file: pxelinux.cfg/{ipaddr_file[:-i]}" 390 assert expected_text_ip in output 391 i += 1 392 393 assert expected_text_default in output 394 assert "Config file 'default.boot' found" in output 395 396@pytest.mark.buildconfigspec("cmd_crc32") 397@pytest.mark.buildconfigspec("cmd_tftpboot") 398@pytest.mark.buildconfigspec("cmd_tftpput") 399def test_net_tftpput(ubman): 400 """Test the tftpput command. 401 402 A file is downloaded from the TFTP server and then uploaded to the TFTP 403 server, its size and its CRC32 are validated. 404 405 The details of the file to download are provided by the boardenv_* file; 406 see the comment at the beginning of this file. 407 """ 408 409 if not net_set_up: 410 pytest.skip("Network not initialized") 411 412 f = ubman.config.env.get("env__net_tftp_readable_file", None) 413 if not f: 414 pytest.skip("No TFTP readable file to read") 415 416 addr = f.get("addr", None) 417 if not addr: 418 addr = utils.find_ram_base(ubman) 419 420 sz = f.get("size", None) 421 timeout = f.get("timeout", ubman.p.timeout) 422 fn = f["fn"] 423 fnu = f.get("fnu", "_".join([datetime.datetime.now().strftime("%y%m%d%H%M%S"), fn])) 424 expected_text = "Bytes transferred = " 425 if sz: 426 expected_text += "%d" % sz 427 428 with ubman.temporary_timeout(timeout): 429 output = ubman.run_command("tftpboot %x %s" % (addr, fn)) 430 431 assert "TIMEOUT" not in output 432 assert expected_text in output 433 434 expected_tftpb_crc = f.get("crc32", None) 435 436 output = ubman.run_command("crc32 $fileaddr $filesize") 437 assert expected_tftpb_crc in output 438 439 with ubman.temporary_timeout(timeout): 440 output = ubman.run_command( 441 "tftpput $fileaddr $filesize $serverip:%s" % (fnu) 442 ) 443 444 expected_text = "Bytes transferred = " 445 if sz: 446 expected_text += "%d" % sz 447 addr = addr + sz 448 assert "TIMEOUT" not in output 449 assert "Access violation" not in output 450 assert expected_text in output 451 452 with ubman.temporary_timeout(timeout): 453 output = ubman.run_command("tftpboot %x %s" % (addr, fnu)) 454 455 expected_text = "Bytes transferred = " 456 if sz: 457 expected_text += "%d" % sz 458 assert "TIMEOUT" not in output 459 assert expected_text in output 460 461 output = ubman.run_command("crc32 $fileaddr $filesize") 462 assert expected_tftpb_crc in output 463