Soft Patch Panel
 help / color / mirror / Atom feed
From: ogawa.yasufumi@lab.ntt.co.jp
To: ferruh.yigit@intel.com, spp@dpdk.org
Cc: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
Subject: [spp] [PATCH 05/15] tools/sppc: add spp-primary app continer
Date: Fri, 15 Jun 2018 17:37:44 +0900	[thread overview]
Message-ID: <20180615083754.20220-6-ogawa.yasufumi@lab.ntt.co.jp> (raw)
In-Reply-To: <20180615083754.20220-1-ogawa.yasufumi@lab.ntt.co.jp>

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

App container launcher is a script for launching application running
on a container. This app container launcher is for SPP primary.

This patch is to add spp-primary app container and helper library used
from app container launcher scripts commonly.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 tools/sppc/app/__init__.py    |   0
 tools/sppc/app/spp-primary.py | 171 +++++++++++++++++++++
 tools/sppc/lib/app_helper.py  | 269 ++++++++++++++++++++++++++++++++++
 3 files changed, 440 insertions(+)
 create mode 100644 tools/sppc/app/__init__.py
 create mode 100755 tools/sppc/app/spp-primary.py
 create mode 100644 tools/sppc/lib/app_helper.py

diff --git a/tools/sppc/app/__init__.py b/tools/sppc/app/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tools/sppc/app/spp-primary.py b/tools/sppc/app/spp-primary.py
new file mode 100755
index 0000000..a3fc9f8
--- /dev/null
+++ b/tools/sppc/app/spp-primary.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+
+import argparse
+import os
+import subprocess
+import sys
+
+work_dir = os.path.dirname(__file__)
+sys.path.append(work_dir + '/..')
+from conf import env
+from lib import app_helper
+from lib import common
+
+target_name = 'spp'
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description="Launcher for spp-primary application container")
+
+    parser = app_helper.add_eal_args(parser)
+
+    # Application specific arguments
+    parser.add_argument(
+        '-n', '--nof-ring',
+        type=int,
+        default=10,
+        help='Maximum number of Ring PMD')
+    parser.add_argument(
+        '-p', '--port-mask',
+        type=str,
+        help='Port mask')
+    parser.add_argument(
+        '-dv', '--dev-vhost-ids',
+        type=str,
+        help='vhost device IDs')
+    parser.add_argument(
+        '-dt', '--dev-tap-ids',
+        type=str,
+        help='TAP device IDs')
+    parser.add_argument(
+        '-ip', '--ctrl-ip',
+        type=str,
+        help="IP address of SPP controller")
+    parser.add_argument(
+        '--ctrl-port',
+        type=int,
+        default=5555,
+        help="Port of SPP controller")
+
+    parser = app_helper.add_sppc_args(parser)
+
+    return parser.parse_args()
+
+
+def main():
+    args = parse_args()
+
+    # Setup docker command.
+    docker_cmd = ['sudo', 'docker', 'run', '\\']
+    docker_opts = []
+
+    # This container is running in backgroud in defualt.
+    if args.foreground is not True:
+        docker_opts += ['-d', '\\']
+    else:
+        docker_opts += ['-it', '\\']
+
+    docker_opts += [
+        '--privileged', '\\',  # should be privileged
+        '-v', '/dev/hugepages:/dev/hugepages', '\\',
+        '-v', '/var/run/:/var/run/', '\\']
+
+    if args.dev_vhost_ids is not None:
+        docker_opts += ['-v', '/tmp:/tmp', '\\']
+
+    # Setup for TAP devices with given device IDs.
+    if args.dev_tap_ids is not None:
+        dev_tap_ids = app_helper.dev_ids_to_list(args.dev_tap_ids)
+    else:
+        dev_tap_ids = []
+
+    # Setup for vhost devices with given device IDs.
+    if args.dev_vhost_ids is not None:
+        dev_vhost_ids = app_helper.dev_ids_to_list(args.dev_vhost_ids)
+        socks = []
+        for dev_id in dev_vhost_ids:
+            socks.append({
+                'host': '/tmp/sock%d' % dev_id,
+                'guest': '/tmp/sock%d' % dev_id})
+    else:
+        dev_vhost_ids = []
+
+    if args.container_image is not None:
+        container_image = args.container_image
+    else:
+        # Container image name, for exp 'sppc/dpdk-ubuntu:18.04'
+        container_image = common.container_img_name(
+            env.CONTAINER_IMG_NAME[target_name],
+            args.dist_name,
+            args.dist_ver)
+
+    docker_opts += [
+        container_image, '\\']
+
+    # Setup spp primary command.
+    cmd_path = '%s/../spp/src/primary/%s/spp_primary' % (
+        env.RTE_SDK, env.RTE_TARGET)
+
+    spp_cmd = [cmd_path, '\\']
+
+    # Do not use 'app_helper.setup_eal_opts()' because spp_primary does
+    # not use virtio vdev but TAP or vhost, which should be added manually.
+    core_opt = app_helper.get_core_opt(args)
+    mem_opt = app_helper.get_mem_opt(args)
+    eal_opts = [
+        core_opt['attr'], core_opt['val'], '\\',
+        '-n', str(args.nof_memchan), '\\',
+        mem_opt['attr'], mem_opt['val'], '\\',
+        '--huge-dir', '/dev/hugepages', '\\',
+        '--proc-type', 'primary', '\\']
+
+    # Add TAP vdevs
+    for i in range(len(dev_tap_ids)):
+        eal_opts += [
+            '--vdev', 'net_tap%d,iface=foo%d' % (
+                dev_tap_ids[i], dev_tap_ids[i]), '\\']
+
+    # Add vhost vdevs
+    for i in range(len(dev_vhost_ids)):
+        eal_opts += [
+            '--vdev', 'eth_vhost%d,iface=%s' % (
+                dev_vhost_ids[i], socks[i]['guest']), '\\']
+
+    eal_opts += ['--', '\\']
+
+    spp_opts = []
+    # Check for other mandatory opitons.
+    if args.port_mask is None:
+        common.error_exit('port_mask')
+    else:
+        spp_opts += ['-p', args.port_mask, '\\']
+
+    spp_opts += ['-n', str(args.nof_ring), '\\']
+
+    # IP address of SPP controller.
+    ctrl_ip = os.getenv('SPP_CTRL_IP', args.ctrl_ip)
+    if ctrl_ip is None:
+        common.error_exit('SPP_CTRL_IP')
+    else:
+        spp_opts += ['-s', '%s:%d' % (ctrl_ip, args.ctrl_port), '\\']
+
+    cmds = docker_cmd + docker_opts + spp_cmd + eal_opts + spp_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)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/sppc/lib/app_helper.py b/tools/sppc/lib/app_helper.py
new file mode 100644
index 0000000..c15c852
--- /dev/null
+++ b/tools/sppc/lib/app_helper.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+
+import common
+import os
+import sys
+
+work_dir = os.path.dirname(__file__)
+sys.path.append(work_dir + '/..')
+from conf import env
+
+
+def add_eal_args(parser, mem_size=1024, mem_channel=4):
+    parser.add_argument(
+        '-l', '--core-list',
+        type=str,
+        help='Core list')
+    parser.add_argument(
+        '-c', '--core-mask',
+        type=str,
+        help='Core mask')
+    parser.add_argument(
+        '-m', '--mem',
+        type=int,
+        default=mem_size,
+        help='Memory size (default is %s)' % mem_size)
+    parser.add_argument(
+        '--socket-mem',
+        type=str,
+        help='Memory size')
+    parser.add_argument(
+        '--nof-memchan',
+        type=int,
+        default=mem_channel,
+        help='Number of memory channels (default is %s)' % mem_channel)
+    return parser
+
+
+def get_core_opt(args):
+    # Check core_mask or core_list is defined.
+    if args.core_mask is not None:
+        core_opt = {'attr': '-c', 'val': args.core_mask}
+    elif args.core_list is not None:
+        core_opt = {'attr': '-l', 'val': args.core_list}
+    else:
+        common.error_exit('core_mask or core_list')
+    return core_opt
+
+
+def get_mem_opt(args):
+    # Check memory option is defined.
+    if args.socket_mem is not None:
+        mem_opt = {'attr': '--socket-mem', 'val': args.socket_mem}
+    else:
+        mem_opt = {'attr': '-m', 'val': str(args.mem)}
+    return mem_opt
+
+
+def setup_eal_opts(args, file_prefix, proc_type='auto', hugedir=None):
+    core_opt = get_core_opt(args)
+    mem_opt = get_mem_opt(args)
+
+    eal_opts = [
+        core_opt['attr'], core_opt['val'], '\\',
+        '-n', str(args.nof_memchan), '\\',
+        mem_opt['attr'], mem_opt['val'], '\\',
+        '--proc-type', proc_type, '\\']
+
+    if args.dev_ids is None:
+        common.error_exit('--dev-ids')
+    else:
+        dev_ids = dev_ids_to_list(args.dev_ids)
+
+    socks = []
+    for dev_id in dev_ids:
+        socks.append({
+            'host': '/tmp/sock%d' % dev_id,
+            'guest': '/var/run/usvhost%d' % dev_id})
+
+    for i in range(len(dev_ids)):
+        eal_opts += [
+            '--vdev', 'virtio_user%d,queues=%d,path=%s' % (
+                dev_ids[i], args.nof_queues, socks[i]['guest']), '\\']
+
+    eal_opts += [
+        '--file-prefix', file_prefix, '\\',
+        '--', '\\']
+
+    return eal_opts
+
+
+def add_sppc_args(parser):
+    parser.add_argument(
+        '--dist-name',
+        type=str,
+        default='ubuntu',
+        help="Name of Linux distribution")
+    parser.add_argument(
+        '--dist-ver',
+        type=str,
+        default='latest',
+        help="Version of Linux distribution")
+    parser.add_argument(
+        '-ci', '--container-image',
+        type=str,
+        help="Name of container image")
+    parser.add_argument(
+        '-fg', '--foreground',
+        action='store_true',
+        help="Run container as foreground mode")
+    parser.add_argument(
+        '--dry-run',
+        action='store_true',
+        help="Only print matrix, do not run, and exit")
+    return parser
+
+
+def setup_docker_opts(args, target_name, sock_files, workdir=None):
+    docker_opts = []
+
+    if args.foreground is True:
+        docker_opts = ['-it', '\\']
+    else:
+        docker_opts = ['-d', '\\']
+
+    if workdir is not None:
+        docker_opts += ['--workdir', workdir, '\\']
+
+    if args.no_privileged is not True:
+        docker_opts += ['--privileged', '\\']
+
+    for sock in sock_files:
+        docker_opts += [
+            '-v', '%s:%s' % (sock['host'], sock['guest']), '\\']
+
+    if args.container_image is not None:
+        container_image = args.container_image
+    else:
+        # Container image name, for exp 'sppc/dpdk-ubuntu:18.04'
+        container_image = common.container_img_name(
+            env.CONTAINER_IMG_NAME[target_name],
+            args.dist_name,
+            args.dist_ver)
+
+    docker_opts += [
+        '-v', '/dev/hugepages:/dev/hugepages', '\\',
+        container_image, '\\']
+
+    return docker_opts
+
+
+def add_appc_args(parser):
+    parser.add_argument(
+        '-d', '--dev-ids',
+        type=str,
+        help='two or more even vhost device IDs')
+    parser.add_argument(
+        '-nq', '--nof-queues',
+        type=int,
+        default=1,
+        help="Number of queues of virtio (default is 1)")
+    parser.add_argument(
+        '--no-privileged',
+        action='store_true',
+        help="Disable docker's privileged mode if it's needed")
+    return parser
+
+
+def uniq(dup_list):
+    """Remove duplicated elements in a list and return a unique list
+
+    Example: [1,1,2,2,3,3] #=> [1,2,3]
+    """
+
+    return list(set(dup_list))
+
+
+def dev_ids_to_list(dev_ids):
+    """Parse vhost device IDs and return as a list.
+
+    Example:
+    '1,3-5' #=> [1,3,4,5]
+    """
+
+    res = []
+    for dev_id_part in dev_ids.split(','):
+        if '-' in dev_id_part:
+            cl = dev_id_part.split('-')
+            res = res + range(int(cl[0]), int(cl[1])+1)
+        else:
+            res.append(int(dev_id_part))
+    return res
+
+
+def is_sufficient_dev_ids(dev_ids, port_mask):
+    """Check if ports can be reserved for dev_ids
+
+    Return true if the number of dev IDs equals or more than given ports.
+    'dev_ids' is a value of '-d' or '--dev-ids' such as '1,2'.
+    """
+
+    dev_ids_list = dev_ids_to_list(dev_ids)
+    if not ('0x' in port_mask):  # invalid port mask
+        return False
+
+    ports_in_binary = format(int(port_mask, 16), 'b')
+    if len(dev_ids_list) >= len(ports_in_binary):
+        return True
+    else:
+        return False
+
+
+def sock_files(dev_ids_list):
+    socks = []
+    for dev_id in dev_ids_list:
+        socks.append({
+            'host': '/tmp/sock%d' % dev_id,
+            'guest': '/var/run/usvhost%d' % dev_id})
+    return socks
+
+
+def count_ports(port_mask):
+    """Return the number of ports of given portmask"""
+
+    ports_in_binary = format(int(port_mask, 16), 'b')
+    nof_ports = ports_in_binary.count('1')
+    return nof_ports
+
+
+def cores_to_list(core_opt):
+    """Expand DPDK core option to ranged list.
+
+    Core option must be a hash of attritute and its value.
+    Attribute is -c(core mask) or -l(core list).
+    For example, '-c 0x03' is described as:
+      core_opt = {'attr': '-c', 'val': '0x03'}
+    or '-l 0-1' is as
+      core_opt = {'attr': '-l', 'val': '0-1'}
+
+    Returned value is a list, such as:
+      '0x17' is converted to [1,2,3,5].
+    or
+      '-l 1-3,5' is converted to [1,2,3,5],
+    """
+
+    res = []
+    if core_opt['attr'] == '-c':
+        bin_list = list(
+            format(
+                int(core_opt['val'], 16), 'b'))
+        cnt = 1
+        bin_list.reverse()
+        for i in bin_list:
+            if i == '1':
+                res.append(cnt)
+            cnt += 1
+    elif core_opt['attr'] == '-l':
+        for core_part in core_opt['val'].split(','):
+            if '-' in core_part:
+                cl = core_part.split('-')
+                res = res + range(int(cl[0]), int(cl[1])+1)
+            else:
+                res.append(int(core_part))
+    else:
+        pass
+    res = uniq(res)
+    res.sort()
+    return res
-- 
2.17.1

  parent reply	other threads:[~2018-06-15  8:38 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-15  8:37 [spp] [PATCH 00/15] Add SPP container tools ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 01/15] tools/sppc: add SPP container build tool ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 02/15] tools/sppc: add dockerfiles for DPDK ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 03/15] tools/sppc: add dockerfiles for pktgen ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 04/15] tools/sppc: add dockerfiles for SPP ogawa.yasufumi
2018-06-15  8:37 ` ogawa.yasufumi [this message]
2018-06-15  8:37 ` [spp] [PATCH 06/15] tools/sppc: add spp-nfv app continer ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 07/15] tools/sppc: add spp-vm " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 08/15] tools/sppc: add l2fwd " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 09/15] tools/sppc: add testpmd " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 10/15] tools/sppc: add l3fwd " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 11/15] tools/sppc: add pktgen " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 12/15] tools/sppc: add load-balancer " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 13/15] tools/sppc: add helloworld " ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 14/15] tools/sppc: add helper script for build ogawa.yasufumi
2018-06-15  8:37 ` [spp] [PATCH 15/15] tools/sppc: add spp launcher script ogawa.yasufumi
2018-08-15 15:34 ` [spp] [PATCH 00/15] Add SPP container tools Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180615083754.20220-6-ogawa.yasufumi@lab.ntt.co.jp \
    --to=ogawa.yasufumi@lab.ntt.co.jp \
    --cc=ferruh.yigit@intel.com \
    --cc=spp@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).