From: oda@valinux.co.jp
To: spp@dpdk.org, ferruh.yigit@intel.com, ogawa.yasufumi@lab.ntt.co.jp
Subject: [spp] [PATCH v2 1/2] spp-ctl: add spp_mirror API support
Date: Thu, 29 Nov 2018 11:04:12 +0900 [thread overview]
Message-ID: <20181129020413.20023-2-oda@valinux.co.jp> (raw)
In-Reply-To: <20181129020413.20023-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
next prev parent reply other threads:[~2018-11-29 2:04 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 ` [spp] [PATCH 1/2] " oda
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 ` oda [this message]
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=20181129020413.20023-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).