Soft Patch Panel
 help / color / mirror / Atom feed
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
To: Itsuro ODA <oda@valinux.co.jp>, spp@dpdk.org
Subject: Re: [spp] [PATCH v2 7/9] spp-ctl: SPP controller with Web API
Date: Tue, 25 Sep 2018 11:01:12 +0900	[thread overview]
Message-ID: <b100adb3-0a92-1733-d993-963a7e475538@lab.ntt.co.jp> (raw)
In-Reply-To: <20180923114410.2D9C.277DD91C@valinux.co.jp>

> I wrote the subject incorrectly.
> It should be "[PATCH v2 7/9] spp-ctl: controller"
Hi,

No problem! I would like to correct it if there is no need to revise for updating to v3.

Thanks,
Yasufumi
> 
> On Sun, 23 Sep 2018 11:36:21 +0900
> Itsuro ODA <oda@valinux.co.jp> wrote:
> 
>> From: Itsuro Oda <oda@valinux.co.jp>
>>
>> Signed-off-by: Itsuro Oda <oda@valinux.co.jp>
>> ---
>>   src/spp-ctl/spp_ctl.py | 158 +++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 158 insertions(+)
>>   create mode 100644 src/spp-ctl/spp_ctl.py
>>
>> diff --git a/src/spp-ctl/spp_ctl.py b/src/spp-ctl/spp_ctl.py
>> new file mode 100644
>> index 0000000..e168747
>> --- /dev/null
>> +++ b/src/spp-ctl/spp_ctl.py
>> @@ -0,0 +1,158 @@
>> +# SPDX-License-Identifier: BSD-3-Clause
>> +# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
>> +
>> +import eventlet
>> +eventlet.monkey_patch()
>> +
>> +import argparse
>> +import errno
>> +import json
>> +import logging
>> +import socket
>> +import subprocess
>> +
>> +import spp_proc
>> +import spp_webapi
>> +
>> +
>> +LOG = logging.getLogger(__name__)
>> +
>> +
>> +MSG_SIZE = 4096
>> +
>> +
>> +class Controller(object):
>> +
>> +    def __init__(self, pri_port, sec_port, api_port):
>> +        self.web_server = spp_webapi.WebServer(self, api_port)
>> +        self.procs = {}
>> +        self.init_connection(pri_port, sec_port)
>> +
>> +    def start(self):
>> +        self.web_server.start()
>> +
>> +    def init_connection(self, pri_port, sec_port):
>> +        self.pri_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>> +        self.pri_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
>> +        self.pri_sock.bind(('127.0.0.1', pri_port))
>> +        self.pri_sock.listen(1)
>> +        self.primary_listen_thread = eventlet.greenthread.spawn(
>> +            self.accept_primary)
>> +
>> +        self.sec_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>> +        self.sec_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
>> +        self.sec_sock.bind(('127.0.0.1', sec_port))
>> +        self.sec_sock.listen(1)
>> +        self.secondary_listen_thread = eventlet.greenthread.spawn(
>> +            self.accept_secondary)
>> +
>> +    def accept_primary(self):
>> +        while True:
>> +            conn, _ = self.pri_sock.accept()
>> +            proc = self.procs.get(spp_proc.ID_PRIMARY)
>> +            if proc is not None:
>> +                LOG.warning("spp_primary reconnect !")
>> +                with proc.sem:
>> +                    try:
>> +                        proc.conn.close()
>> +                    except Exception:
>> +                        pass
>> +                    proc.conn = conn
>> +                # NOTE: when spp_primary restart, all secondarys must be
>> +                # restarted. this is out of controle of spp-ctl.
>> +            else:
>> +                LOG.info("primary connected.")
>> +                self.procs[spp_proc.ID_PRIMARY] = spp_proc.PrimaryProc(conn)
>> +
>> +    def accept_secondary(self):
>> +        while True:
>> +            conn, _ = self.sec_sock.accept()
>> +            LOG.debug("sec accepted: get process id")
>> +            proc = self._get_proc(conn)
>> +            if proc is None:
>> +                LOG.error("get process id failed")
>> +                conn.close()
>> +                continue
>> +            old_proc = self.procs.get(proc.id)
>> +            if old_proc:
>> +                LOG.warning("%s(%d) reconnect !", old_proc.type, old_proc.id)
>> +                if old_proc.type != proc.type:
>> +                    LOG.warning("type changed ! new type: %s", proc.type)
>> +                with old_proc.sem:
>> +                    try:
>> +                        old_proc.conn.close()
>> +                    except Exception:
>> +                        pass
>> +            else:
>> +                LOG.info("%s(%d) connected.", proc.type, proc.id)
>> +            self.procs[proc.id] = proc
>> +
>> +    @staticmethod
>> +    def _continue_recv(conn):
>> +        try:
>> +            # must set non-blocking to recieve remining data not to happen
>> +            # blocking here.
>> +            # NOTE: usually MSG_DONTWAIT flag is used for this purpose but
>> +            # this flag is not supported under eventlet.
>> +            conn.setblocking(False)
>> +            data = b""
>> +            while True:
>> +                try:
>> +                    rcv_data = conn.recv(MSG_SIZE)
>> +                    data += rcv_data
>> +                    if len(rcv_data) < MSG_SIZE:
>> +                        break
>> +                except socket.error as e:
>> +                    if e.args[0] == errno.EAGAIN:
>> +                        # OK, no data remining. this happens when recieve data
>> +                        # length is just multiple of MSG_SIZE.
>> +                        break
>> +                    raise e
>> +            return data
>> +        finally:
>> +            conn.setblocking(True)
>> +
>> +    @staticmethod
>> +    def _send_command(conn, command):
>> +        conn.sendall(command.encode())
>> +        data = conn.recv(MSG_SIZE)
>> +        if data and len(data) == MSG_SIZE:
>> +            # could not receive data at once. recieve remining data.
>> +            data += self._continue_recv(conn)
>> +        if data:
>> +            data = data.decode()
>> +        return data
>> +
>> +    def _get_proc(self, conn):
>> +        # it is a bit ad hoc. send "_get_clinet_id" command and try to
>> +        # decode reply for each proc type. if success, that is the type.
>> +        data = self._send_command(conn, "_get_client_id")
>> +        for proc in [spp_proc.VfProc, spp_proc.NfvProc]:
>> +            sec_id = proc._decode_client_id(data)
>> +            if sec_id is not None:
>> +                return proc(sec_id, conn)
>> +
>> +    def get_processes(self):
>> +        procs = []
>> +        for proc in self.procs.values():
>> +            p = {"type": proc.type}
>> +            if proc.id != spp_proc.ID_PRIMARY:
>> +                p["client-id"] = proc.id
>> +            procs.append(p)
>> +        return procs
>> +
>> +
>> +def main():
>> +    parser = argparse.ArgumentParser(description="SPP Controller")
>> +    parser.add_argument("-p", dest='pri_port', type=int, default=5555,
>> +                        action='store', help="primary port")
>> +    parser.add_argument("-s", dest='sec_port', type=int, default=6666,
>> +                        action='store', help="secondary port")
>> +    parser.add_argument("-a", dest='api_port', type=int, default=7777,
>> +                        action='store', help="web api port")
>> +    args = parser.parse_args()
>> +
>> +    logging.basicConfig(level=logging.DEBUG)
>> +
>> +    controller = Controller(args.pri_port, args.sec_port, args.api_port)
>> +    controller.start()
>> -- 
>> 2.17.0
>> -- 
>> Itsuro ODA <oda@valinux.co.jp>
>

  reply	other threads:[~2018-09-25  2:03 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-23  2:22 [spp] [PATCH v2 0/9] " Itsuro ODA
2018-09-23  2:25 ` [spp] [PATCH v2 1/9] docs: overview Itsuro ODA
2018-10-02  3:29   ` Yasufumi Ogawa
2018-09-23  2:28 ` [spp] [PATCH v2 2/9] docs: api reference Itsuro ODA
2018-10-02  3:42   ` Yasufumi Ogawa
2018-10-02  4:10     ` Yasufumi Ogawa
2018-09-23  2:30 ` [spp] [PATCH v2 3/9] docs: index Itsuro ODA
2018-09-23  2:32 ` [spp] [PATCH v2 4/9] docs: top index Itsuro ODA
2018-09-23  2:33 ` [spp] PATCH v2 5/9] add requirements.txt Itsuro ODA
2018-09-23  2:35 ` [spp] [PATCH v2 6/9] spp-ctl: executable Itsuro ODA
2018-10-02  5:47   ` Yasufumi Ogawa
2018-09-23  2:36 ` [spp] [PATCH v2 7/9] spp-ctl: SPP controller with Web API Itsuro ODA
2018-09-23  2:44   ` Itsuro ODA
2018-09-25  2:01     ` Yasufumi Ogawa [this message]
2018-09-23  2:38 ` [spp] [PATCH v2 8/9] spp-ctl: web api handler Itsuro ODA
2018-10-02  4:03   ` Yasufumi Ogawa
2018-09-23  2:39 ` [spp] [PATCH v2 9/9] spp-ctl: spp command interface Itsuro ODA

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=b100adb3-0a92-1733-d993-963a7e475538@lab.ntt.co.jp \
    --to=ogawa.yasufumi@lab.ntt.co.jp \
    --cc=oda@valinux.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).