Soft Patch Panel
 help / color / mirror / Atom feed
From: oda@valinux.co.jp
To: spp@dpdk.org, ferruh.yigit@intel.com, ogawa.yasufumi@lab.ntt.co.jp
Subject: [spp] [PATCH 1/2] spp_mirror API support
Date: Thu, 29 Nov 2018 09:55:11 +0900	[thread overview]
Message-ID: <20181129005512.18526-2-oda@valinux.co.jp> (raw)
In-Reply-To: <20181129005512.18526-1-oda@valinux.co.jp>

From: Itsuro Oda <oda@valinux.co.jp>

This patch adds spp_mirror APIs to spp-ctl.

Signed-off-by: Itsuro Oda <oda@valinux.co.jp>
---
 src/spp-ctl/spp_ctl.py    |   2 +-
 src/spp-ctl/spp_proc.py   |  57 +++++++++++++-----
 src/spp-ctl/spp_webapi.py | 120 ++++++++++++++++++++++++++------------
 3 files changed, 127 insertions(+), 52 deletions(-)

diff --git a/src/spp-ctl/spp_ctl.py b/src/spp-ctl/spp_ctl.py
index 0576ae1..279c180 100644
--- a/src/spp-ctl/spp_ctl.py
+++ b/src/spp-ctl/spp_ctl.py
@@ -128,7 +128,7 @@ class Controller(object):
         # 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]:
+        for proc in [spp_proc.VfProc, spp_proc.NfvProc, spp_proc.MirrorProc]:
             sec_id = proc._decode_client_id(data)
             if sec_id is not None:
                 return proc(sec_id, conn)
diff --git a/src/spp-ctl/spp_proc.py b/src/spp-ctl/spp_proc.py
index 83c59ea..648e085 100644
--- a/src/spp-ctl/spp_proc.py
+++ b/src/spp-ctl/spp_proc.py
@@ -15,6 +15,7 @@ ID_PRIMARY = 0
 TYPE_PRIMARY = "primary"
 TYPE_VF = "vf"
 TYPE_NFV = "nfv"
+TYPE_MIRROR = "mirror"
 
 
 def exec_command(func):
@@ -53,10 +54,10 @@ class SppProc(object):
         self.conn = conn
 
 
-class VfProc(SppProc):
+class VfCommon(SppProc):
 
-    def __init__(self, id, conn):
-        super(VfProc, self).__init__(TYPE_VF, id, conn)
+    def __init__(self, proc_type, id, conn):
+        super(VfCommon, self).__init__(proc_type, id, conn)
 
     @staticmethod
     def _decode_reply(data):
@@ -67,14 +68,6 @@ class VfProc(SppProc):
             raise bottle.HTTPError(400, "command error: %s" % msg)
         return data
 
-    @staticmethod
-    def _decode_client_id(data):
-        try:
-            data = VfProc._decode_reply(data)
-            return data["client_id"]
-        except:
-            return None
-
     @exec_command
     def get_status(self):
         return "status"
@@ -88,6 +81,25 @@ class VfProc(SppProc):
     def stop_component(self, comp_name):
         return "component stop {comp_name}".format(**locals())
 
+    @exec_command
+    def port_del(self, port, direction, comp_name):
+        return "port del {port} {direction} {comp_name}".format(**locals())
+
+
+class VfProc(VfCommon):
+
+    def __init__(self, id, conn):
+        super(VfProc, self).__init__(TYPE_VF, id, conn)
+
+    @staticmethod
+    def _decode_client_id(data):
+        try:
+            data = VfCommon._decode_reply(data)
+            if data["process_type"] == TYPE_VF:
+                return data["client_id"]
+        except:
+            return None
+
     @exec_command
     def port_add(self, port, direction, comp_name, op, vlan_id, pcp):
         command = "port add {port} {direction} {comp_name}".format(**locals())
@@ -97,10 +109,6 @@ class VfProc(SppProc):
                 command += " %d %d" % (vlan_id, pcp)
         return command
 
-    @exec_command
-    def port_del(self, port, direction, comp_name):
-        return "port del {port} {direction} {comp_name}".format(**locals())
-
     @exec_command
     def set_classifier_table(self, mac_address, port):
         return ("classifier_table add mac {mac_address} {port}"
@@ -124,6 +132,25 @@ class VfProc(SppProc):
                 .format(**locals()))
 
 
+class MirrorProc(VfCommon):
+
+    def __init__(self, id, conn):
+        super(MirrorProc, self).__init__(TYPE_MIRROR, id, conn)
+
+    @staticmethod
+    def _decode_client_id(data):
+        try:
+            data = VfCommon._decode_reply(data)
+            if data["process_type"] == TYPE_MIRROR:
+                return data["client_id"]
+        except:
+            return None
+
+    @exec_command
+    def port_add(self, port, direction, comp_name):
+        return "port add {port} {direction} {comp_name}".format(**locals())
+
+
 class NfvProc(SppProc):
 
     def __init__(self, id, conn):
diff --git a/src/spp-ctl/spp_webapi.py b/src/spp-ctl/spp_webapi.py
index 48cc1c4..7547f0e 100644
--- a/src/spp-ctl/spp_webapi.py
+++ b/src/spp-ctl/spp_webapi.py
@@ -114,6 +114,7 @@ class WebServer(BaseHandler):
     /          WebServer
     /v1          V1Handler
        /vfs        V1VFHandler
+       /mirrors    V1MirrorHandler
        /nfvs       V1NFVHandler
        /primary    V1PrimaryHandler
     """
@@ -141,6 +142,7 @@ class V1Handler(BaseHandler):
         self.set_route()
 
         self.mount("/vfs", V1VFHandler(controller))
+        self.mount("/mirrors", V1MirrorHandler(controller))
         self.mount("/nfvs", V1NFVHandler(controller))
         self.mount("/primary", V1PrimaryHandler(controller))
 
@@ -154,7 +156,46 @@ class V1Handler(BaseHandler):
         return self.ctrl.get_processes()
 
 
-class V1VFHandler(BaseHandler):
+class V1VFCommon(object):
+    """Define common methods for vf and mirror handler."""
+
+    def convert_info(self, data):
+        info = data["info"]
+        vf = {}
+        vf["client-id"] = info["client-id"]
+        vf["ports"] = []
+        for key in ["phy", "vhost", "ring"]:
+            for idx in info[key]:
+                vf["ports"].append(key + ":" + str(idx))
+        vf["components"] = info["core"]
+        if "classifier_table" in info:
+            vf["classifier_table"] = info["classifier_table"]
+
+        return vf
+
+    def validate_comp_start(self, body, types):
+        for key in ['name', 'core', 'type']:
+            if key not in body:
+                raise KeyRequired(key)
+        if not isinstance(body['name'], str):
+            raise KeyInvalid('name', body['name'])
+        if not isinstance(body['core'], int):
+            raise KeyInvalid('core', body['core'])
+        if body['type'] not in types:
+            raise KeyInvalid('type', body['type'])
+
+    def validate_comp_port(self, body):
+        for key in ['action', 'port', 'dir']:
+            if key not in body:
+                raise KeyRequired(key)
+        if body['action'] not in ["attach", "detach"]:
+            raise KeyInvalid('action', body['action'])
+        if body['dir'] not in ["rx", "tx"]:
+            raise KeyInvalid('dir', body['dir'])
+        self._validate_port(body['port'])
+
+
+class V1VFHandler(BaseHandler, V1VFCommon):
 
     def __init__(self, controller):
         super(V1VFHandler, self).__init__(controller)
@@ -177,50 +218,18 @@ class V1VFHandler(BaseHandler):
         self.route('/<sec_id:int>/classifier_table', 'PUT',
                    callback=self.vf_classifier)
 
-    def convert_vf_info(self, data):
-        info = data["info"]
-        vf = {}
-        vf["client-id"] = info["client-id"]
-        vf["ports"] = []
-        for key in ["phy", "vhost", "ring"]:
-            for idx in info[key]:
-                vf["ports"].append(key + ":" + str(idx))
-        vf["components"] = info["core"]
-        vf["classifier_table"] = info["classifier_table"]
-
-        return vf
-
     def vf_get(self, proc):
-        return self.convert_vf_info(proc.get_status())
-
-    def _validate_vf_comp_start(self, body):
-        for key in ['name', 'core', 'type']:
-            if key not in body:
-                raise KeyRequired(key)
-        if not isinstance(body['name'], str):
-            raise KeyInvalid('name', body['name'])
-        if not isinstance(body['core'], int):
-            raise KeyInvalid('core', body['core'])
-        if body['type'] not in ["forward", "merge", "classifier_mac"]:
-            raise KeyInvalid('type', body['type'])
+        return self.convert_info(proc.get_status())
 
     def vf_comp_start(self, proc, body):
-        self._validate_vf_comp_start(body)
+        self.validate_comp_start(body, ["forward", "merge", "classifier_mac"])
         proc.start_component(body['name'], body['core'], body['type'])
 
     def vf_comp_stop(self, proc, name):
         proc.stop_component(name)
 
     def _validate_vf_comp_port(self, body):
-        for key in ['action', 'port', 'dir']:
-            if key not in body:
-                raise KeyRequired(key)
-        if body['action'] not in ["attach", "detach"]:
-            raise KeyInvalid('action', body['action'])
-        if body['dir'] not in ["rx", "tx"]:
-            raise KeyInvalid('dir', body['dir'])
-        self._validate_port(body['port'])
-
+        self.validate_comp_port(body)
         if body['action'] == "attach":
             vlan = body.get('vlan')
             if vlan:
@@ -296,6 +305,45 @@ class V1VFHandler(BaseHandler):
                     mac_address, port, body['vlan'])
 
 
+class V1MirrorHandler(BaseHandler, V1VFCommon):
+
+    def __init__(self, controller):
+        super(V1MirrorHandler, self).__init__(controller)
+        self.type = spp_proc.TYPE_MIRROR
+
+        self.set_route()
+
+        self.install(self.check_sec_id)
+        self.install(self.get_body)
+        self.install(self.make_response)
+
+    def set_route(self):
+        self.route('/<sec_id:int>', 'GET', callback=self.mirror_get)
+        self.route('/<sec_id:int>/components', 'POST',
+                   callback=self.mirror_comp_start)
+        self.route('/<sec_id:int>/components/<name>', 'DELETE',
+                   callback=self.mirror_comp_stop)
+        self.route('/<sec_id:int>/components/<name>/ports', 'PUT',
+                   callback=self.mirror_comp_port)
+
+    def mirror_get(self, proc):
+        return self.convert_info(proc.get_status())
+
+    def mirror_comp_start(self, proc, body):
+        self.validate_comp_start(body, ["mirror"])
+        proc.start_component(body['name'], body['core'], body['type'])
+
+    def mirror_comp_stop(self, proc, name):
+        proc.stop_component(name)
+
+    def mirror_comp_port(self, proc, name, body):
+        self.validate_comp_port(body)
+        if body['action'] == "attach":
+            proc.port_add(body['port'], body['dir'], name)
+        else:
+            proc.port_del(body['port'], body['dir'], name)
+
+
 class V1NFVHandler(BaseHandler):
 
     def __init__(self, controller):
-- 
2.17.1

  reply	other threads:[~2018-11-29  0:55 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-29  0:55 [spp] [PATCH 0/2] " oda
2018-11-29  0:55 ` oda [this message]
2018-11-29  0:55 ` [spp] [PATCH 2/2] spp_mirror API api-reference oda
2018-11-29  1:36 ` [spp] [PATCH 0/2] spp_mirror API support Yasufumi Ogawa
2018-11-29  2:04 ` [spp] [PATCH v2 " oda
2018-11-29  2:04   ` [spp] [PATCH v2 1/2] spp-ctl: add " oda
2018-11-29  2:04   ` [spp] [PATCH v2 2/2] docs: add spp_mirror API api-reference oda
2018-11-29 10:01   ` [spp] [PATCH v2 0/2] spp_mirror API support Yasufumi Ogawa

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=20181129005512.18526-2-oda@valinux.co.jp \
    --to=oda@valinux.co.jp \
    --cc=ferruh.yigit@intel.com \
    --cc=ogawa.yasufumi@lab.ntt.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).