| import os |
| import time |
| |
| import infra.basetest |
| |
| |
| class TestPppd(infra.basetest.BRTest): |
| # This test needs a Kernel with ppp support. |
| kern_frag = \ |
| infra.filepath("tests/package/test_pppd/linux-ppp.fragment") |
| # Our test config also enables socat and iproute2 used as |
| # supporting tools for this test. |
| config = \ |
| f""" |
| BR2_aarch64=y |
| BR2_TOOLCHAIN_EXTERNAL=y |
| BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0" |
| BR2_LINUX_KERNEL=y |
| BR2_LINUX_KERNEL_CUSTOM_VERSION=y |
| BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.57" |
| BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y |
| BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config" |
| BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{kern_frag}" |
| BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y |
| BR2_PACKAGE_IPROUTE2=y |
| BR2_PACKAGE_PPPD=y |
| BR2_PACKAGE_SOCAT=y |
| BR2_TARGET_ROOTFS_CPIO=y |
| BR2_TARGET_ROOTFS_CPIO_GZIP=y |
| # BR2_TARGET_ROOTFS_TAR is not set |
| """ |
| |
| def test_run(self): |
| img = os.path.join(self.builddir, "images", "rootfs.cpio.gz") |
| kern = os.path.join(self.builddir, "images", "Image") |
| self.emulator.boot(arch="aarch64", |
| kernel=kern, |
| kernel_cmdline=["console=ttyAMA0"], |
| options=["-M", "virt", "-cpu", "cortex-a57", "-m", "256M", "-initrd", img]) |
| self.emulator.login() |
| |
| # We define our socat output log file. |
| socat_log = "/tmp/socat.log" |
| |
| # We define two PTY names we will use for this test. |
| pty0 = "/dev/ttyppp0" |
| pty1 = "/dev/ttyppp1" |
| |
| # We define two IP addresses. |
| local_ip = "192.168.12.34" |
| remote_ip = "10.20.30.40" |
| |
| # We define few parameters for our ping. |
| ping_count = 3 |
| ping_size = 32 |
| ping_payload = "aa" |
| |
| # We check the program can execute. |
| self.assertRunOk("pppd --version") |
| |
| # We create two PTYs connected to each other with socat. We |
| # will connect a pppd on each one to create connection end |
| # points. We also enable some debugging to print the content |
| # of packets forwarded by socat. We will use that to later |
| # validate data actually passed through this channel. Note: we |
| # start the command in a subshell to suppress the job control |
| # message, when this background process will be killed later |
| # in this test. |
| cmd = "( socat -d2 -x -lu" |
| cmd += f" PTY,link={pty0},rawer,b115200 PTY,link={pty1},rawer,b115200" |
| cmd += f" > {socat_log} 2>&1 & )" |
| self.assertRunOk(cmd) |
| |
| # We create a network namespace. We will use it to isolate one |
| # of the two pppd instances (our fake remote). We do so to |
| # make sure our network test will not use the default routes |
| # (or local loopback). This will make sure our communication |
| # data will go through our PPP link. |
| namespace = "remote-ppp" |
| self.assertRunOk(f"ip netns add {namespace}") |
| |
| # We start our (fake) remote pppd instance, in our netns. |
| cmd = f"ip netns exec {namespace} " |
| cmd += f"pppd noauth ifname ppp1 {pty1} {remote_ip}:{local_ip}" |
| self.assertRunOk(cmd) |
| |
| # We wait a bit for the pppd to settle... |
| time.sleep(3) |
| |
| # We start out local pppd instance, this time in the default |
| # network namespace. |
| cmd = f"pppd noauth ifname ppp0 {pty0} {local_ip}:{remote_ip}" |
| self.assertRunOk(cmd) |
| |
| # We wait again... |
| time.sleep(3) |
| |
| # We check we can ping our two IPs. The local IP is expected |
| # to go through the interface loopback (and not go through our |
| # PPP link). Only the remote IP ping is expected to go through |
| # our socat PTYs. |
| for ip in local_ip, remote_ip: |
| cmd = f"ping -c {ping_count} -s {ping_size} -p {ping_payload} {ip}" |
| self.assertRunOk(cmd) |
| |
| # We stop our pppd and socat processes. |
| self.assertRunOk("killall pppd") |
| self.assertRunOk("killall socat") |
| |
| # For debugging this test, it can be useful to print the socat |
| # log on the console. Uncomment this line, if needed. |
| # self.assertRunOk(f"cat {socat_log}") |
| |
| # The actual ping payload set with our payload_data is |
| # slightly smaller as the ping packet size, due other data |
| # written by the ping command. This is why we subtract 4 bytes |
| # to the size. |
| pattern = " ".join([ping_payload] * (ping_size - 4)) |
| # We count the number of packets with this payload transmitted |
| # through socat... |
| out, ret = self.emulator.run(f"grep -Fc '{pattern}' {socat_log}") |
| self.assertEqual(ret, 0) |
| # We check we have exactly twice our requested ping count (one |
| # for ICMP ECHO, one for the REPLY). |
| self.assertEqual(int(out[0]), ping_count * 2) |