[spp] [PATCH 1/2] spp_mirror API support

oda at valinux.co.jp oda at valinux.co.jp
Thu Nov 29 01:55:11 CET 2018


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

This patch adds spp_mirror APIs to spp-ctl.

Signed-off-by: Itsuro Oda <oda at 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



More information about the spp mailing list