Soft Patch Panel
 help / color / mirror / Atom feed
From: x-fn-spp@sl.ntt-tx.co.jp
To: spp@dpdk.org
Subject: [spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py
Date: Thu, 28 Dec 2017 13:55:54 +0900	[thread overview]
Message-ID: <201712280456.vBS4u8Gp011168@imss03.silk.ntt-tx.co.jp> (raw)
In-Reply-To: <4aae78ff-3b6c-cdfe-a8b7-24ec08b73935@lab.ntt.co.jp>

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add spp_vf.py as a modified version of spp.py.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/spp_vf.py | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 443 insertions(+)
 create mode 100755 src/spp_vf.py

diff --git a/src/spp_vf.py b/src/spp_vf.py
new file mode 100755
index 0000000..40310db
--- /dev/null
+++ b/src/spp_vf.py
@@ -0,0 +1,443 @@
+#!/usr/bin/python
+"""Soft Patch Panel"""
+
+from __future__ import print_function
+from Queue import Queue
+from thread import start_new_thread
+from threading import Thread
+import cmd
+import getopt
+import select
+import socket
+import sys
+
+import json
+
+class GrowingList(list):
+    """GrowingList"""
+
+    def __setitem__(self, index, value):
+        if index >= len(self):
+            self.extend([None]*(index + 1 - len(self)))
+        list.__setitem__(self, index, value)
+
+MAX_SECONDARY = 16
+
+# init
+PRIMARY = ''
+SECONDARY_LIST = []
+SECONDARY_COUNT = 0
+
+#init primary comm channel
+MAIN2PRIMARY = Queue()
+PRIMARY2MAIN = Queue()
+
+#init secondary comm channel list
+MAIN2SEC = GrowingList()
+SEC2MAIN = GrowingList()
+
+def connectionthread(name, client_id, conn, m2s, s2m):
+    """Manage secondary process connections"""
+
+    cmd_str = 'hello'
+
+    #infinite loop so that function do not terminate and thread do not end.
+    while True:
+        try:
+            _, _, _ = select.select([conn,], [conn,], [], 5)
+        except select.error:
+            break
+
+        #Sending message to connected secondary
+        try:
+            cmd_str = m2s.get(True)
+            conn.send(cmd_str) #send only takes string
+        except KeyError:
+            break
+        except Exception, excep:
+            print (str(excep))
+            break
+
+        #Receiving from secondary
+        try:
+            data = conn.recv(1024) # 1024 stands for bytes of data to be received
+            if data:
+                s2m.put("recv:" + str(conn.fileno()) + ":" + "{" + data + "}")
+            else:
+                s2m.put("closing:" + str(conn))
+                break
+        except Exception, excep:
+            print (str(excep))
+            break
+
+    SECONDARY_LIST.remove(client_id)
+    conn.close()
+
+def getclientid(conn):
+    """Get client_id from client"""
+
+    try:
+        conn.send("_get_client_id")
+        #conn.send("{\"commands\":[{\"command\":\"process\"}]}")
+    except KeyError:
+        return -1
+
+    data = conn.recv(1024)
+    if data == None:
+        return -1
+
+    #client_id = int(data.strip('\0'))
+    json_dict = json.loads(data)
+    client_id = int(json_dict['client_id'])
+
+    if client_id < 0 or client_id > MAX_SECONDARY:
+        return -1
+
+    print ("secondary id %d" % client_id)
+    return client_id
+
+    found = 0
+    for i in SECONDARY_LIST:
+        if client_id == i:
+            found = 1
+            break
+
+    if found == 0:
+        return client_id
+
+    # client_id in use, find a free one
+    free_client_id = -1
+    for i in range(MAX_SECONDARY):
+        found = -1
+        for j in SECONDARY_LIST:
+            if i == j:
+                found = i
+                break
+        if found == -1:
+            free_client_id = i
+            break
+
+    if free_client_id < 0:
+        return -1
+
+    conn.send("_set_client_id %u" % free_client_id)
+    data = conn.recv(1024)
+
+    return free_client_id
+
+def acceptthread(sock, main2sec, sec2main):
+    """Listen for secondary processes"""
+
+    global SECONDARY_COUNT
+
+    try:
+        while True:
+            #Accepting incoming connections
+            conn, _ = sock.accept()
+
+            client_id = getclientid(conn)
+            if client_id < 0:
+                break
+
+            #Creating new thread.
+            #Calling secondarythread function for this function and passing
+            #conn as argument.
+
+            SECONDARY_LIST.append(client_id)
+            main2sec[client_id] = Queue()
+            sec2main[client_id] = Queue()
+            start_new_thread(connectionthread,
+                             ('secondary', client_id, conn,
+                              main2sec[client_id],
+                              sec2main[client_id], ))
+            SECONDARY_COUNT += 1
+    except Exception, excep:
+        print (str(excep))
+        sock.close()
+
+def command_primary(command):
+    """Send command to primary process"""
+
+    if PRIMARY:
+        MAIN2PRIMARY.put(command)
+        print (PRIMARY2MAIN.get(True))
+    else:
+        print ("primary not started")
+
+def command_secondary(sec_id, command):
+    """Send command to secondary process with sec_id"""
+
+    if sec_id in SECONDARY_LIST:
+        MAIN2SEC[sec_id].put(command)
+        print (SEC2MAIN[sec_id].get(True))
+    else:
+        print ("secondary id %d not exist" % sec_id)
+
+def print_status():
+    """Display information about connected clients"""
+
+    print ("Soft Patch Panel Status :")
+    print ("primary: %d" % PRIMARY)
+    print ("secondary count: %d" % len(SECONDARY_LIST))
+    for i in SECONDARY_LIST:
+        print ("Connected secondary id: %d" % i)
+
+def primarythread(sock, main2primary, primary2main):
+    """Manage primary process connection"""
+
+    global PRIMARY
+    cmd_str = ''
+
+    while True:
+        #waiting for connection
+        PRIMARY = False
+        conn, addr = sock.accept()
+        PRIMARY = True
+
+        while conn:
+            try:
+                _, _, _ = select.select([conn,], [conn,], [], 5)
+            except select.error:
+                break
+
+            #Sending message to connected primary
+            try:
+                cmd_str = main2primary.get(True)
+                conn.send(cmd_str) #send only takes string
+            except KeyError:
+                break
+            except Exception, excep:
+                print (str(excep))
+                break
+
+            #Receiving from primary
+            try:
+                data = conn.recv(1024) # 1024 stands for bytes of data to be received
+                if data:
+                    primary2main.put("recv:" + str(addr) + ":" + "{" + data + "}")
+                else:
+                    primary2main.put("closing:" + str(addr))
+                    conn.close()
+                    break
+            except Exception, excep:
+                print (str(excep))
+                break
+
+    print ("primary communication thread end")
+
+def close_all_secondary():
+    """Exit all secondary processes"""
+
+    return;
+
+    global SECONDARY_COUNT
+
+    tmp_list = []
+    for i in SECONDARY_LIST:
+        tmp_list.append(i)
+    for i in tmp_list:
+        command_secondary(i, 'exit')
+    SECONDARY_COUNT = 0
+
+def check_sec_cmds(cmds):
+    """Validate secondary commands before sending"""
+
+    return 1
+
+    level1 = ['status', 'exit', 'forward', 'stop']
+    level2 = ['add', 'patch', 'del']
+    patch_args = ['reset']
+    add_del_args = ['ring', 'vhost']
+    cmdlist = cmds.split(' ')
+    valid = 0
+
+    length = len(cmdlist)
+    if length == 1:
+        if cmdlist[0] in level1:
+            valid = 1
+    elif length == 2:
+        if cmdlist[0] == 'patch':
+            if cmdlist[1] in patch_args:
+                valid = 1
+    elif length == 3:
+        if cmdlist[0] in level2:
+            if cmdlist[0] == 'add' or cmdlist[0] == 'del':
+                if cmdlist[1] in add_del_args:
+                    if str.isdigit(cmdlist[2]):
+                        valid = 1
+            elif cmdlist[0] == 'patch':
+                if str.isdigit(cmdlist[1]) and str.isdigit(cmdlist[2]):
+                    valid = 1
+
+    return valid
+
+class Shell(cmd.Cmd):
+    """SPP command prompt"""
+
+    intro = 'Welcome to the spp.   Type help or ? to list commands.\n'
+    prompt = 'spp > '
+    recorded_file = None
+
+    COMMANDS = ['status', 'add', 'patch', 'ring', 'vhost',
+                'reset', 'exit', 'forward', 'stop', 'clear']
+
+    def complete_pri(self, text, line, begidx, endidx):
+        """Completion for primary process commands"""
+
+        if not text:
+            completions = self.COMMANDS[:]
+        else:
+            completions = [p
+                           for p in self.COMMANDS
+                           if p.startswith(text)
+                          ]
+        return completions
+
+    def complete_sec(self, text, line, begidx, endidx):
+        """Completion for secondary process commands"""
+
+        if not text:
+            completions = self.COMMANDS[:]
+        else:
+            completions = [p
+                           for p in self.COMMANDS
+                           if p.startswith(text)
+                          ]
+        return completions
+
+    def do_status(self, _):
+        """Display Soft Patch Panel Status"""
+
+        print_status()
+
+    def do_pri(self, command):
+        """Send command to primary process"""
+
+        if command and command in self.COMMANDS:
+            command_primary(command)
+        else:
+            print ("primary invalid command")
+
+    def do_sec(self, arg):
+        """Send command to secondary process"""
+
+        cmds = arg.split(';')
+        if len(cmds) < 2:
+            print ("error")
+        elif str.isdigit(cmds[0]):
+            sec_id = int(cmds[0])
+            if check_sec_cmds(cmds[1]):
+                command_secondary(sec_id, cmds[1])
+            else:
+                print ("invalid cmd")
+        else:
+            print (cmds[0])
+            print ("first %s" % cmds[1])
+
+    def do_record(self, arg):
+        """Save future commands to filename:  RECORD filename.cmd"""
+
+        self.recorded_file = open(arg, 'w')
+
+    def do_playback(self, arg):
+        """Playback commands from a file:  PLAYBACK filename.cmd"""
+
+        self.close()
+        try:
+            with open(arg) as recorded_file:
+                lines = []
+                for line in recorded_file:
+                    if line.strip().startswith("#"):
+                        continue
+                    lines.append(line)
+                self.cmdqueue.extend(lines)
+        except IOError:
+            print ("Error: File does not exist.")
+
+    def precmd(self, line):
+        line = line.lower()
+        if self.recorded_file and 'playback' not in line:
+            print(line, file=self.recorded_file)
+        return line
+
+    def close(self):
+        """Close record file"""
+
+        if self.recorded_file:
+            print("closing file")
+            self.recorded_file.close()
+            self.recorded_file = None
+
+    def do_bye(self, arg):
+        """Stop recording, close SPP, and exit: BYE"""
+
+        cmds = arg.split(' ')
+        if cmds[0] == 'sec':
+            close_all_secondary()
+        elif cmds[0] == 'all':
+            close_all_secondary()
+            command_primary('exit')
+        elif cmds[0] == '':
+            print('Thank you for using Soft Patch Panel')
+            self.close()
+            return True
+
+def main(argv):
+    """main"""
+
+    # Defining server address and port
+    host = ''  #'localhost' or '127.0.0.1' or '' are all same
+
+    try:
+        opts, _ = getopt.getopt(argv, "p:s:h", ["help", "primary = ", "secondary"])
+    except getopt.GetoptError:
+        print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt in ("-h", "--help"):
+            print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+            sys.exit()
+        elif opt in ("-p", "--primary"):
+            primary_port = int(arg)
+            print ("primary port : %d" % primary_port)
+        elif opt in ("-s", "--secondary"):
+            secondary_port = int(arg)
+            print ('secondary port : %d' % secondary_port)
+
+    #Creating primary socket object
+    primary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+    #Binding primary socket to a address. bind() takes tuple of host and port.
+    primary_sock.bind((host, primary_port))
+
+    #Listening primary at the address
+    primary_sock.listen(1) #5 denotes the number of clients can queue
+
+    primary_thread = Thread(target=primarythread,
+                            args=(primary_sock, MAIN2PRIMARY, PRIMARY2MAIN,))
+    primary_thread.daemon = True
+    primary_thread.start()
+
+    #Creating secondary socket object
+    secondary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+    #Binding secondary socket to a address. bind() takes tuple of host and port.
+    secondary_sock.bind((host, secondary_port))
+
+    #Listening secondary at the address
+    secondary_sock.listen(MAX_SECONDARY)
+
+    # secondary process handling thread
+    start_new_thread(acceptthread, (secondary_sock, MAIN2SEC, SEC2MAIN))
+
+    shell = Shell()
+    shell.cmdloop()
+    shell = None
+
+    primary_sock.shutdown(socket.SHUT_RDWR)
+    primary_sock.close()
+    secondary_sock.shutdown(socket.SHUT_RDWR)
+    secondary_sock.close()
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
-- 
1.9.1

  parent reply	other threads:[~2017-12-28  4:56 UTC|newest]

Thread overview: 97+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-25  4:41 [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Nakamura Hioryuki
2017-12-26  1:54 ` Yasufumi Ogawa
2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
2017-12-28  8:49     ` Yasufumi Ogawa
2017-12-28  4:55   ` [spp] [PATCH 02/57] spp_vf: support multi process x-fn-spp
2018-02-07 16:50     ` Ferruh Yigit
2018-02-08  1:21       ` Yasufumi Ogawa
2018-02-08  6:44       ` [spp] [spp 02168] " Nakamura Hioryuki
2017-12-28  4:55   ` [spp] [PATCH 03/57] spp_vf: comment out check of using cores x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 04/57] spp_vf: modify classifier for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 05/57] spp_vf: add procedure that mac address is null x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 06/57] spp_vf: change config format for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 07/57] spp_vf: fix compiler warning in classifier_mac.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 08/57] spp_vf: modify data struct for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 09/57] spp_vf: add functions of command acceptance x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 10/57] spp_vf: add command acceptance calling x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 11/57] spp_vf: fix compiler warning in command_proc.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 12/57] " x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 13/57] spp_vf: refactor command acceptance/decode x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 14/57] spp_vf: fix return value overwrite problem x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 15/57] spp_vf: initialize message buffer x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 16/57] spp_vf: add const keyword to parameter x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 17/57] spp_vf: fix wrong comparison operator x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 18/57] spp_vf: fix wrong variable to be assigned x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 19/57] spp_vf: refactor parsing server ip address x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 20/57] spp_vf: fix error in command decode x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 21/57] spp_vf: fix comparison operator in spp_vf.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 22/57] spp_vf: check upper limit to the number of process x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 23/57] spp_vf: display usage message x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 24/57] spp_vf: split command processing source file x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 25/57] spp_vf: add new log and line break x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 26/57] spp_vf: support get-process-id command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 27/57] spp_vf: update socket creation procedure x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 28/57] spp_vf: change log level and add line break x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 29/57] spp_vf: replace unsupported jansson api x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 30/57] spp_vf: change order of command result in json object x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 31/57] spp_vf: use prediction keywords x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 32/57] spp_vf: fix wrong comparison x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 33/57] spp_vf: update sending error status x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 34/57] spp_vf: modify conditional statement x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 35/57] spp_vf: add proc on receiving l2 multicast x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 36/57] spp_vf: extend limit on number of usable cores x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 37/57] spp_vf: add restart procedure for vhost client x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 38/57] spp_vf: fix classifier mbuf handling x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 39/57] spp_vf: add status command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 40/57] spp_vf: add output source information in error log x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 41/57] spp_vf: change function names x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 42/57] spp_vf: change how to request commands x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 43/57] spp_vf: update command decode procedure x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 44/57] spp_vf: remove debug log output procedures x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 45/57] spp_vf: improve command_decoder program code x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 46/57] spp_vf: fix a bug in status command x-fn-spp
2017-12-28  4:55   ` x-fn-spp [this message]
2017-12-28  4:55   ` [spp] [PATCH 48/57] spp_vf: refactor for commnets in spp_vf.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 49/57] spp_vf: refactor comments in classifier_mac.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 50/57] spp_vf: refactor comments in spp_forward.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 51/57] spp_vf: refactor for commnets in spp_config.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 52/57] spp_vf: refactor no self-explanatory comments x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 53/57] spp_vf: correct typo of function name x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 54/57] spp_vf: support new command x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 55/57] spp_vf: add display of status command x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 56/57] spp_vf: fix " x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 57/57] spp_vf: fix l2 multicast packet forwarding x-fn-spp
2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
2018-01-19  0:52     ` Yasufumi Ogawa
2018-01-22 14:37       ` Ferruh Yigit
2018-01-23  0:25         ` Yasufumi Ogawa
2018-01-16  5:16   ` [spp] [PATCH 02/30] doc: add how_to_use.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 03/30] doc: add config_manual.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 04/30] doc: add spp_vf.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 05/30] doc: revise spp_vf.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 06/30] doc: add config section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 07/30] doc: update jp setup manual x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 08/30] doc: modify figure in spp_vf_overview x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 09/30] doc: fix " x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 10/30] doc: fix figure in overview x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 11/30] doc: add sample usage x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 12/30] doc: revice path descs x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 13/30] doc: add network configuration diagram x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 14/30] doc: update user account x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 15/30] doc: update descriptions for todo x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 16/30] doc: add description for explanation section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 17/30] doc: add spp_sample_usage_svg in docs/spp_vf/ x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 18/30] doc: add explanation for terminating spp app x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 19/30] doc: add explanations on options of spp x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 20/30] doc: update description for the latest spp version x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 21/30] doc: update description on dpdk version x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 22/30] doc: fix vm setup procedure for network config x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 23/30] doc: update jansson installation procedure x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 24/30] doc: fix required network configuration x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 25/30] doc: add how to use vhost-user support x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 26/30] doc: add references to hugepages and isolcpus x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 27/30] doc: remove description on classifier_table x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 28/30] doc: fix typos and erros in texts x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 29/30] doc: update sample config section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 30/30] doc: align figure title position x-fn-spp

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=201712280456.vBS4u8Gp011168@imss03.silk.ntt-tx.co.jp \
    --to=x-fn-spp@sl.ntt-tx.co.jp \
    --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).