[spp] [PATCH 7/9] controller: update generating graph
ogawa.yasufumi at lab.ntt.co.jp
ogawa.yasufumi at lab.ntt.co.jp
Mon Mar 12 06:35:22 CET 2018
From: Yasufumi Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
Update parsing network configuration and generating graph in Topo class
since resource information held in secondary is changed from 18.02.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
---
src/controller/topo.py | 237 +++++++++++++++++++++++++------------------------
1 file changed, 119 insertions(+), 118 deletions(-)
diff --git a/src/controller/topo.py b/src/controller/topo.py
index 92d1634..0fc529b 100644
--- a/src/controller/topo.py
+++ b/src/controller/topo.py
@@ -3,11 +3,13 @@
import os
import re
+import spp_common
from spp_common import logger
import subprocess
import traceback
import uuid
import websocket
+import yaml
class Topo(object):
@@ -31,7 +33,8 @@ class Topo(object):
res_ary = []
for sec_id in self.sec_ids:
self.m2s_queues[sec_id].put("status")
- res = self.format_sec_status(self.s2m_queues[sec_id].get(True))
+ res = self.format_sec_status(
+ sec_id, self.s2m_queues[sec_id].get(True))
res_ary.append(res)
if dtype == "http":
self.to_http(res_ary)
@@ -45,7 +48,8 @@ class Topo(object):
res_ary = []
for sec_id in self.sec_ids:
self.m2s_queues[sec_id].put("status")
- res = self.format_sec_status(self.s2m_queues[sec_id].get(True))
+ res = self.format_sec_status(
+ sec_id, self.s2m_queues[sec_id].get(True))
res_ary.append(res)
if ftype == "dot":
@@ -64,58 +68,63 @@ class Topo(object):
def to_dot(self, sec_list, output_fname):
# Label given if outport is "none"
- NO_PORT = "none"
+ NO_PORT = None
# Graphviz params
+ # TODO(yasufum) consider to move gviz params to config file.
SEC_COLORS = [
"blue", "green", "orange", "chocolate", "black",
"cyan3", "green3", "indianred", "lawngreen", "limegreen"]
PORT_COLORS = {
- "PHY": "white",
- "RING": "yellow",
- "VHOST": "limegreen"}
+ "phy": "white",
+ "ring": "yellow",
+ "vhost": "limegreen"}
LINE_STYLE = {
- "RUNNING": "solid",
- "IDLING": "dashed"}
+ "running": "solid",
+ "idling": "dashed"}
GRAPH_TYPE = "digraph"
LINK_TYPE = "->"
node_attrs = 'node[shape="rectangle", style="filled"];'
+ node_template = '%s' + spp_common.delim_node + '%s'
+
phys = []
rings = []
vhosts = []
links = []
+ # parse status message from sec.
for sec in sec_list:
for port in sec["ports"]:
- if port["iface"]["type"] == "PHY":
+ if port["iface"]["type"] == "phy":
phys.append(port)
- elif port["iface"]["type"] == "RING":
+ elif port["iface"]["type"] == "ring":
rings.append(port)
- elif port["iface"]["type"] == "VHOST":
+ elif port["iface"]["type"] == "vhost":
vhosts.append(port)
else:
raise ValueError(
"Invaid interface type: %s" % port["iface"]["type"])
- if port["out"] != NO_PORT:
- out_id = int(port["out"])
- if sec["forward"] is True:
- l_style = LINE_STYLE["RUNNING"]
+ if port['out'] != NO_PORT:
+ out_type, out_id = port['out'].split(':')
+ if sec['status'] == 'running':
+ l_style = LINE_STYLE["running"]
else:
- l_style = LINE_STYLE["IDLING"]
+ l_style = LINE_STYLE["idling"]
attrs = '[label="%s", color="%s", style="%s"]' % (
- "sec" + sec["sec_id"],
- SEC_COLORS[int(sec["sec_id"])],
+ "sec%d" % sec["sec_id"],
+ SEC_COLORS[sec["sec_id"]],
l_style
)
- tmp = "%s%s %s %s%s%s;" % (
+ link_style = node_template + ' %s ' + node_template + '%s;'
+ tmp = link_style % (
port["iface"]["type"],
port["iface"]["id"],
LINK_TYPE,
- sec["ports"][out_id]["iface"]["type"],
- sec["ports"][out_id]["iface"]["id"],
+ out_type,
+ out_id,
attrs
)
links.append(tmp)
@@ -124,51 +133,61 @@ class Topo(object):
output.append("newrank=true;")
output.append(node_attrs)
- phy_labels = []
- for p in phys:
- phy_labels.append(p["iface"]["type"] + p["iface"]["id"])
- phy_labels = list(set(phy_labels))
- for l in phy_labels:
+ phy_nodes = []
+ for node in phys:
+ phy_nodes.append(
+ node_template % (node['iface']['type'], node['iface']['id']))
+ phy_nodes = list(set(phy_nodes))
+ for node in phy_nodes:
+ label = re.sub(
+ r'%s' % spp_common.delim_node, spp_common.delim_label, node)
output.append(
- '%s[label="%s", fillcolor="%s"];' % (
- l, l, PORT_COLORS["PHY"]))
+ '%s[label="%s", fillcolor="%s"];' % (
+ node, label, PORT_COLORS["phy"]))
- ring_labels = []
+ ring_nodes = []
for p in rings:
- ring_labels.append(p["iface"]["type"] + p["iface"]["id"])
- ring_labels = list(set(ring_labels))
- for l in ring_labels:
+ ring_nodes.append(
+ node_template % (p['iface']['type'], p['iface']['id']))
+ ring_nodes = list(set(ring_nodes))
+ for node in ring_nodes:
+ label = re.sub(
+ r'%s' % spp_common.delim_node, spp_common.delim_label, node)
output.append(
'%s[label="%s", fillcolor="%s"];' % (
- l, l, PORT_COLORS["RING"]))
+ node, label, PORT_COLORS["ring"]))
- vhost_labels = []
+ vhost_nodes = []
for p in vhosts:
- vhost_labels.append(p["iface"]["type"] + p["iface"]["id"])
- vhost_labels = list(set(vhost_labels))
- for l in vhost_labels:
+ vhost_nodes.append(
+ node_template % (p["iface"]["type"], p["iface"]["id"]))
+ vhost_nodes = list(set(vhost_nodes))
+ for node in vhost_nodes:
+ label = re.sub(
+ r'%s' % spp_common.delim_node, spp_common.delim_label, node)
output.append(
'%s[label="%s", fillcolor="%s"];' % (
- l, l, PORT_COLORS["VHOST"]))
+ node, label, PORT_COLORS["vhost"]))
# rank
output.append(
- '{rank=same; %s}' % ("; ".join(ring_labels)))
+ '{rank=same; %s}' % ("; ".join(ring_nodes)))
output.append(
- '{rank=same; %s}' % ("; ".join(vhost_labels)))
+ '{rank=same; %s}' % ("; ".join(vhost_nodes)))
+ rank_style = '{rank=max; %s}' % node_template
if len(phys) > 0:
output.append(
- '{rank=max; %s}' % (
- phys[0]["iface"]["type"] + phys[0]["iface"]["id"]))
+ rank_style % (
+ phys[0]["iface"]["type"], phys[0]["iface"]["id"]))
elif len(vhosts) > 0:
output.append(
- '{rank=max; %s}' % (
- vhosts[0]["iface"]["type"] + vhosts[0]["iface"]["id"]))
+ rank_style % (
+ vhosts[0]["iface"]["type"], vhosts[0]["iface"]["id"]))
- if len(phy_labels) > 0:
+ if len(phy_nodes) > 0:
output.append(
- '{rank=same; %s}' % ("; ".join(phy_labels)))
+ '{rank=same; %s}' % ("; ".join(phy_nodes)))
# Add subgraph
ssgs = []
@@ -177,24 +196,26 @@ class Topo(object):
for label, val in self.sub_graphs.items():
cluster_id = "cluster%d" % cnt
ssg_label = label
- ssg_ports = val
+ ssg_ports = re.sub(
+ r'%s' % spp_common.delim_label,
+ spp_common.delim_node, val)
ssg = 'subgraph %s {label="%s" %s}' % (
- cluster_id, ssg_label, ssg_ports)
+ cluster_id, ssg_label, ssg_ports)
ssgs.append(ssg)
cnt += 1
cluster_id = "cluster0"
sg_label = "Host"
- sg_ports = "; ".join(phy_labels + ring_labels)
+ sg_ports = "; ".join(phy_nodes + ring_nodes)
if len(ssgs) == 0:
output.append(
- 'subgraph %s {label="%s" %s}' % (
- cluster_id, sg_label, sg_ports))
+ 'subgraph %s {label="%s" %s}' % (
+ cluster_id, sg_label, sg_ports))
else:
tmp = 'label="%s" %s' % (sg_label, sg_ports)
contents = [tmp] + ssgs
output.append(
- 'subgraph %s {%s}' % (cluster_id, '; '.join(contents)))
+ 'subgraph %s {%s}' % (cluster_id, '; '.join(contents)))
# Add links
for link in links:
@@ -255,85 +276,65 @@ class Topo(object):
subprocess.call("%s %s" % (img_cmd, tmpfile), shell=True)
subprocess.call(["rm", "-f", tmpfile])
- def format_sec_status(self, stat):
+ def format_sec_status(self, sec_id, stat):
"""Return formatted secondary status as a hash
By running status command on controller, status is sent from
secondary process and receiving message is displayed.
This is an example of receiving status message.
- recv:8:{Client ID 1 Idling
- client_id:1
- port_id:0,on,PHY,outport:2
- port_id:1,on,PHY,outport:none
- port_id:2,on,RING(0),outport:3
- port_id:3,on,VHOST(1),outport:none
- }
-
- This method returns as following.
- {
- 'forward': False,
+
+ spp > sec 1;status
+ status: idling
+ ports:
+ - 'phy:0 -> vhost:1'
+ - 'phy:1'
+ - 'ring:0'
+ - 'vhost:1 -> ring:0'
+
+ This method returns a result as following.
+ {
+ 'sec_id': '1',
+ 'status': 'idling',
'ports': [
- {
- 'out': 'none',
- 'id': '0',
- 'iface': {'type': 'PHY', 'id': '0'}
- },
- {
- 'out': 'none',
- 'id': '1',
- 'iface': {'type': 'PHY', 'id': '1'}
- }
+ {
+ 'rid': 'phy:0',
+ 'out': 'vhost:0',
+ 'iface': {'type': 'phy', 'id': '0'}
+ },
+ {
+ 'rid': 'phy:1',
+ 'out': None,
+ 'iface': {'type': 'phy', 'id': '1'}
+ }
],
- 'sec_id': '2'
- }
+ 'sec_id': '2',
+ ...
+ }
"""
- stat_ary = stat.split("\n")
+ stat_obj = yaml.load(stat)
res = {}
+ res['sec_id'] = sec_id
+ res['status'] = stat_obj['status']
+ port_list = []
try:
- # Check running status
- if "Idling" in stat_ary[0]:
- res["forward"] = False
- elif "Running" in stat_ary[0]:
- res["forward"] = True
- else:
- print("Invalid forwarding status:", stat_ary[0])
-
- ptn = re.compile(r"clinet_id:(\d+)")
- m = ptn.match(stat_ary[1])
- if m is not None:
- res["sec_id"] = m.group(1)
- else:
- raise Exception("No client ID matched!")
-
- ports = []
- # match PHY, for exp. 'port_id:0,on,PHY,outport:none'
- ptn_p = re.compile(r"port_id:(\d+),on,(\w+),outport:(\w+)")
-
- # match RING for exp. 'port_id:2,on,RING(0),outport:3'
- # or VHOST for exp. 'port_id:3,on,VHOST(1),outport:none'
- ptn_v = re.compile(
- r"port_id:(\d+),on,(\w+)\((\d+)\),outport:(\w+)")
-
- for i in range(2, len(stat_ary)-1):
- m = ptn_p.match(stat_ary[i])
- if m is not None:
- ports.append({
- "id": m.group(1),
- "iface": {"type": m.group(2), "id": m.group(1)},
- "out": m.group(3)})
- continue
-
- m = ptn_v.match(stat_ary[i])
- if m is not None:
- ports.append({
- "id": m.group(1),
- "iface": {"type": m.group(2), "id": m.group(3)},
- "out": m.group(4)})
-
- res["ports"] = ports
+ ports = stat_obj['ports'].split(',')
+ for port_info in ports:
+ rid, outport = port_info.split('-')
+ if outport == 'null':
+ outport = None
+
+ itype, pid = rid.split(':')
+ iface = {'type': itype, 'id': pid}
+ port_list.append({
+ 'rid': rid,
+ 'out': outport,
+ 'iface': iface
+ })
+
+ res["ports"] = port_list
return res
except Exception:
--
2.7.4
More information about the spp
mailing list