1.7. How to Define Your App Launcher

SPP container is a set of python script for launching DPDK application on a container with docker command. You can launch your own application by preparing a container image and install your application in the container. In this chapter, you will understand how to define application container for your application.

1.7.1. Build Image

SPP container provides a build tool with version specific Dockerfiles. You should read the Dockerfiles to understand environmental variable or command path are defined. Build tool refer conf/env.py for the definitions before running docker build.

Dockerfiles of pktgen or SPP can help your understanding for building app container in which your application is placed outside of DPDK’s directory. On the other hand, if you build an app container of DPDK sample application, you do not need to prepare your Dockerfile because all of examples are compiled while building DPDK’s image.

1.7.2. Create App Container Script

As explained in App Container Launchers, app container script shold be prepared for each of applications. Application of SPP container is roughly categorized as DPDK sample apps or not. The former case is like that you change an existing DPDK sample application and run as a app container.

For DPDK sample apps, it is easy to build image and create app container script. On the other hand, it is a bit complex because you should you should define environmental variables, command path and compilation process by your own.

This section describes how to define app container script, first for DPDK sample applications, and then second for other than them.

1.7.3. DPDK Sample App Container

Procedure of App container script is defined in main() and consists of three steps of (1)parsing options, (2)building docker command and (3)application command run inside the container.

Here is a sample code of Helloworld Container. parse_args() is defined in each of app container scripts to parse all of EAL, docker and application specific options. It returns a result of parse_args() method of argparse.ArgumentParser class. App container script uses standard library module argparse for parsing the arguments.

def main():
    args = parse_args()

    # Check for other mandatory opitons.
    if args.dev_ids is None:
        common.error_exit('--dev-ids')

    # Setup for vhost devices with given device IDs.
    dev_ids_list = app_helper.dev_ids_to_list(args.dev_ids)
    sock_files = app_helper.sock_files(dev_ids_list)

Each of options is accessible as args.dev_ids or args.core_list. Before step (2) and (3), you had better to check given option, expecially mandatory options. In this case, --dev-ids is the mandatory and you should terminate the application if it is not given. common.error_exit() is a helper method to print an error message for given option and do exit().

Setup of dev_ids_list and sock_files is required for launching container. lib/app_helper.py defines helper functions commonly used for app containers.

Then, setup docker command and its options as step (2). Docker options are setup by using helper method setup_docker_opts() which generates commonly used options for app containers. This methods returns a list of a part of options to give it to subprocess.call().

# Setup docker command.
docker_cmd = ['sudo', 'docker', 'run', '\\']
docker_opts = app_helper.setup_docker_opts(
    args, target_name, sock_files)

You should notice a option target_name. It is used as a label to choose which of container image you use. The name of container image is defined as a combination of basename, distribution name and version. Basename is defined as a member of CONTAINER_IMG_NAME in conf/env.py.

# defined in conf/env.py
CONTAINER_IMG_NAME = {
    'dpdk': 'sppc/dpdk',
    'pktgen': 'sppc/pktgen',
    'spp': 'sppc/spp'}

This usecase is for DPDK sample app, so you should define target as dpdk. You do not need to change for using DPDK sample apps in general. But it can be changed by using other target name. For example, if you give target pktgen and use default dist name and verion of ubuntu and latest, The name of image is sppc/pktgen-ubuntu:latest.

For using images other than defined above, you can override it with --container-image option. It enables to use any of container images and applications.

You also notice that docker_cmd has \\ at the end of the list. It is only used to format the printed command on the terminal. If you do no care about formatting, you do not need to add it.

Next step is (3), to setup the application command. You should change cmd_path and file_prefix to specify the application. For cmd_path, helloworld should be changed to other name of application, for example,

# Setup helloworld run on container.
cmd_path = '%s/examples/helloworld/%s/helloworld' % (
    env.RTE_SDK, env.RTE_TARGET)

hello_cmd = [cmd_path, '\\']

file_prefix = 'spp-hello-container%d' % dev_ids_list[0]
eal_opts = app_helper.setup_eal_opts(args, file_prefix)

# No application specific options for helloworld
hello_opts = []

file_prefix for EAL option should be unique on the system because it is used as the name of hugepage file. In SPP container, it is a combination of fixed text and vhost device ID because this ID is unique in SPP container and cannot be overlapped, at least among app containers in SPP container. EAL options are also generated by helper method.

Finally, combine all of commands and its options and launch from subprocess.call().

cmds = docker_cmd + docker_opts + hello_cmd + eal_opts + hello_opts
if cmds[-1] == '\\':
    cmds.pop()
common.print_pretty_commands(cmds)

if args.dry_run is True:
    exit()

# Remove delimiters for print_pretty_commands().
while '\\' in cmds:
    cmds.remove('\\')
subprocess.call(cmds)

All of commands and options are combined in to a list cmds to give it to subprocess.call(). You can ignore procedures for \\ and common.print_pretty_commands() if you do not care about printing commands in the terminal. However, you should not to shortcut for args.dry_run because it is very important for users to check the command syntax before running it.

1.7.4. App Container not for DPDK Sample

There are several application using DPDK but not included in sample applications. pktgen.py is an example of this type of app container. As described in DPDK Sample App Container, app container consists of three steps and it is the same for this case.

First of all, you define parsing option for EAL, docker and your application.

def parse_args():
    parser = argparse.ArgumentParser(
        description="Launcher for pktgen-dpdk application container")

    parser = app_helper.add_eal_args(parser)
    parser = app_helper.add_appc_args(parser)

    parser.add_argument(
        '-s', '--pcap-file',
        type=str,
        help="PCAP packet flow file of port, defined as 'N:filename'")
    parser.add_argument(
        '-f', '--script-file',
        type=str,
        help="Pktgen script (.pkt) to or a Lua script (.lua)")
    ...

    parser = app_helper.add_sppc_args(parser)
    return parser.parse_args()

It is almost the same as DPDK Sample App Container, but it has options for pktgen itself. For your application, you can simply add options to parser object.

def main():
    args = parse_args()

    # Setup for vhost devices with given device IDs.
    dev_ids_list = app_helper.dev_ids_to_list(args.dev_ids)
    sock_files = app_helper.sock_files(dev_ids_list)

    # Setup docker command.
    docker_cmd = ['sudo', 'docker', 'run', '\\']
    docker_opts = app_helper.setup_docker_opts(
        args, target_name, sock_files,
        '%s/../pktgen-dpdk' % env.RTE_SDK)

    cmd_path = '%s/../pktgen-dpdk/app/%s/pktgen' % (
        env.RTE_SDK, env.RTE_TARGET)

Setup for docker command is the same as the example. The terget_name might be different from the image you will use, but you do not need to care about which of container image is used because it is overriden with given image with --container-image option. However, you should care about the path of application cmd_path which is run in the container.

Then, you should decide file_prefix to your application container be unique on the system. The file_prefix of SPP container is named as spp-[APP_NAME]-container[VHOST_ID] convensionally to it be unique.

# Setup pktgen command
pktgen_cmd = [cmd_path, '\\']

file_prefix = 'spp-pktgen-container%d' % dev_ids_list[0]
eal_opts = app_helper.setup_eal_opts(args, file_prefix)

You should check the arguments for the application.

...
if args.pcap_file is not None:
    pktgen_opts += ['-s', args.pcap_file, '\\']

if args.script_file is not None:
    pktgen_opts += ['-f', args.script_file, '\\']

if args.log_file is not None:
    pktgen_opts += ['-l', args.log_file, '\\']
...

Finally, combine all of commands and its options and launch from subprocess.call().

cmds = docker_cmd + docker_opts + pktgen_cmd + eal_opts + pktgen_opts
if cmds[-1] == '\\':
    cmds.pop()
common.print_pretty_commands(cmds)

if args.dry_run is True:
    exit()

# Remove delimiters for print_pretty_commands().
while '\\' in cmds:
    cmds.remove('\\')
subprocess.call(cmds)

As you can see, it is almost the same as DPDK sample app container without application path and options of application specific.