Merge branch 'coretk' into coretk-painttool

This commit is contained in:
Huy Pham 2019-12-19 08:46:56 -08:00
commit 62afbbae56
12 changed files with 397 additions and 220 deletions

View file

@ -445,13 +445,16 @@ class CoreClient:
def start_session(self):
nodes = [x.core_node for x in self.canvas_nodes.values()]
links = list(self.links.values())
links = [x.link for x in self.links.values()]
wlan_configs = self.get_wlan_configs_proto()
mobility_configs = self.get_mobility_configs_proto()
emane_model_configs = self.get_emane_model_configs_proto()
hooks = list(self.hooks.values())
service_configs = self.get_service_configs_proto()
file_configs = self.get_service_file_configs_proto()
asymmetric_links = [
x.asymmetric_link for x in self.links.values() if x.asymmetric_link
]
if self.emane_config:
emane_config = {x: self.emane_config[x].value for x in self.emane_config}
else:
@ -471,6 +474,7 @@ class CoreClient:
mobility_configs,
service_configs,
file_configs,
asymmetric_links,
)
self.set_metadata()
process_time = time.perf_counter() - start
@ -602,7 +606,7 @@ class CoreClient:
:return: nothing
"""
node_protos = [x.core_node for x in self.canvas_nodes.values()]
link_protos = list(self.links.values())
link_protos = [x.link for x in self.links.values()]
if self.state != core_pb2.SessionState.DEFINITION:
self.client.set_session_state(
self.session_id, core_pb2.SessionState.DEFINITION
@ -813,8 +817,8 @@ class CoreClient:
interface_one=src_interface,
interface_two=dst_interface,
)
self.links[edge.token] = link
return link
edge.set_link(link)
self.links[edge.token] = edge
def get_wlan_configs_proto(self):
configs = []

View file

@ -5,33 +5,54 @@ import logging
import tkinter as tk
from tkinter import ttk
from core.api.grpc import core_pb2
from coretk.dialogs.colorpicker import ColorPicker
from coretk.dialogs.dialog import Dialog
from coretk.themes import PADX, PADY
def get_int(var):
value = var.get()
if value != "":
return int(value)
else:
return None
def get_float(var):
value = var.get()
if value != "":
return float(value)
else:
return None
class LinkConfiguration(Dialog):
def __init__(self, master, app, edge):
super().__init__(master, app, "link configuration", modal=True)
super().__init__(master, app, "Link Configuration", modal=True)
self.app = app
self.edge = edge
self.is_symmetric = True
self.is_symmetric = edge.link.options.unidirectional is False
if self.is_symmetric:
self.symmetry_var = tk.StringVar(value=">>")
else:
self.symmetry_var = tk.StringVar(value="<<")
self.bandwidth = tk.DoubleVar()
self.delay = tk.DoubleVar()
self.jitter = tk.DoubleVar()
self.loss = tk.DoubleVar()
self.duplicate = tk.DoubleVar()
self.color = tk.StringVar(value="#000000")
self.width = tk.DoubleVar()
self.bandwidth = tk.StringVar()
self.delay = tk.StringVar()
self.jitter = tk.StringVar()
self.loss = tk.StringVar()
self.duplicate = tk.StringVar()
self.down_bandwidth = tk.DoubleVar()
self.down_delay = tk.DoubleVar()
self.down_jitter = tk.DoubleVar()
self.down_loss = tk.DoubleVar()
self.down_duplicate = tk.DoubleVar()
self.down_bandwidth = tk.StringVar()
self.down_delay = tk.StringVar()
self.down_jitter = tk.StringVar()
self.down_loss = tk.StringVar()
self.down_duplicate = tk.StringVar()
self.color = tk.StringVar(value="#000000")
self.color_button = None
self.width = tk.DoubleVar()
self.load_link_config()
self.symmetric_frame = None
@ -44,17 +65,16 @@ class LinkConfiguration(Dialog):
source_name = self.app.canvas.nodes[self.edge.src].core_node.name
dest_name = self.app.canvas.nodes[self.edge.dst].core_node.name
label = ttk.Label(
self.top,
text="Link from %s to %s" % (source_name, dest_name),
anchor=tk.CENTER,
self.top, text=f"Link from {source_name} to {dest_name}", anchor=tk.CENTER
)
label.grid(row=0, column=0, sticky="nsew")
label.grid(row=0, column=0, sticky="ew", pady=PADY)
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(row=1, column=0, sticky="nsew")
button = ttk.Button(frame, text="unlimited")
button.grid(row=0, column=0, sticky="nsew")
frame.grid(row=1, column=0, sticky="ew", pady=PADY)
button = ttk.Button(frame, text="Unlimited")
button.grid(row=0, column=0, sticky="ew", padx=PADX)
if self.is_symmetric:
button = ttk.Button(
frame, textvariable=self.symmetry_var, command=self.change_symmetry
@ -63,128 +83,239 @@ class LinkConfiguration(Dialog):
button = ttk.Button(
frame, textvariable=self.symmetry_var, command=self.change_symmetry
)
button.grid(row=0, column=1, sticky="nsew")
button.grid(row=0, column=1, sticky="ew")
if self.is_symmetric:
self.symmetric_frame = self.get_frame()
self.symmetric_frame.grid(row=2, column=0, sticky="nsew")
self.symmetric_frame.grid(row=2, column=0, sticky="ew", pady=PADY)
else:
self.asymmetric_frame = self.get_frame()
self.asymmetric_frame.grid(row=2, column=0, sticky="nsew")
self.asymmetric_frame.grid(row=2, column=0, sticky="ew", pady=PADY)
self.draw_spacer(row=3)
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(row=3, column=0, sticky="nsew")
button = ttk.Button(frame, text="Apply", command=self.apply)
button.grid(row=0, column=0, sticky="nsew")
frame.grid(row=4, column=0, sticky="ew")
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew", padx=PADX)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="nsew")
button.grid(row=0, column=1, sticky="ew")
def get_frame(self):
main_frame = ttk.Frame(self.top)
main_frame.columnconfigure(0, weight=1)
frame = ttk.Frame(self.top)
frame.columnconfigure(1, weight=1)
if self.is_symmetric:
label_name = "Symmetric link effects: "
label_name = "Symmetric Link Effects"
else:
label_name = "Asymmetric effects: downstream / upstream "
label_name = "Asymmetric Effects: Downstream / Upstream "
row = 0
label = ttk.Label(main_frame, text=label_name, anchor=tk.CENTER)
label.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text=label_name, anchor=tk.CENTER)
label.grid(row=row, column=0, columnspan=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Bandwidth (bps): ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.bandwidth)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Bandwidth (bps)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.bandwidth,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
if not self.is_symmetric:
entry = ttk.Entry(frame, textvariable=self.down_bandwidth)
entry.grid(row=0, column=2, sticky="nsew")
entry = ttk.Entry(
frame,
textvariable=self.down_bandwidth,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Delay (us): ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.delay)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Delay (us)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.delay,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
if not self.is_symmetric:
entry = ttk.Entry(frame, textvariable=self.down_delay)
entry.grid(row=0, column=2, sticky="nsew")
entry = ttk.Entry(
frame,
textvariable=self.down_delay,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Jitter (us): ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.jitter)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Jitter (us)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.jitter,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
if not self.is_symmetric:
entry = ttk.Entry(frame, textvariable=self.down_jitter)
entry.grid(row=0, column=2, sticky="nsew")
entry = ttk.Entry(
frame,
textvariable=self.down_jitter,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Loss (%): ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.loss)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Loss (%)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.loss,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
if not self.is_symmetric:
entry = ttk.Entry(frame, textvariable=self.down_loss)
entry.grid(row=0, column=1, sticky="nsew")
entry = ttk.Entry(
frame,
textvariable=self.down_loss,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Duplicate (%): ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.duplicate)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Duplicate (%)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.duplicate,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
if not self.is_symmetric:
entry = ttk.Entry(frame, textvariable=self.down_duplicate)
entry.grid(row=0, column=1, sticky="nsew")
entry = ttk.Entry(
frame,
textvariable=self.down_duplicate,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Color: ")
label.grid(row=0, column=0, sticky="nsew")
button = ttk.Button(frame, textvariable=self.color)
button.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Color")
label.grid(row=row, column=0, sticky="ew")
self.color_button = tk.Button(
frame,
textvariable=self.color,
background=self.color.get(),
bd=0,
relief=tk.FLAT,
highlightthickness=0,
command=self.click_color,
)
self.color_button.grid(row=row, column=1, sticky="ew", pady=PADY)
row = row + 1
frame = ttk.Frame(main_frame)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=4)
frame.grid(row=row, column=0, sticky="nsew")
label = ttk.Label(frame, text="Width: ")
label.grid(row=0, column=0, sticky="nsew")
entry = ttk.Entry(frame, textvariable=self.width)
entry.grid(row=0, column=1, sticky="nsew")
label = ttk.Label(frame, text="Width")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.width,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
return main_frame
return frame
def apply(self):
def click_color(self):
dialog = ColorPicker(self, self.app, self.color.get())
color = dialog.askcolor()
self.color.set(color)
self.color_button.config(background=color)
def click_apply(self):
logging.debug("click apply")
width = self.width.get()
self.app.canvas.itemconfigure(self.edge.id, width=width)
self.app.canvas.itemconfigure(self.edge.id, width=self.width.get())
self.app.canvas.itemconfigure(self.edge.id, fill=self.color.get())
link = self.edge.link
bandwidth = get_int(self.bandwidth)
jitter = get_int(self.jitter)
delay = get_int(self.delay)
duplicate = get_int(self.duplicate)
loss = get_float(self.loss)
options = core_pb2.LinkOptions(
bandwidth=bandwidth, jitter=jitter, delay=delay, dup=duplicate, per=loss
)
link.options.CopyFrom(options)
interface_one = None
if link.HasField("interface_one"):
interface_one = link.interface_one.id
interface_two = None
if link.HasField("interface_two"):
interface_two = link.interface_two.id
if not self.is_symmetric:
link.options.unidirectional = True
asym_interface_one = None
if interface_one:
asym_interface_one = core_pb2.Interface(id=interface_one)
asym_interface_two = None
if interface_two:
asym_interface_two = core_pb2.Interface(id=interface_two)
down_bandwidth = get_int(self.down_bandwidth)
down_jitter = get_int(self.down_jitter)
down_delay = get_int(self.down_delay)
down_duplicate = get_int(self.down_duplicate)
down_loss = get_float(self.down_loss)
options = core_pb2.LinkOptions(
bandwidth=down_bandwidth,
jitter=down_jitter,
delay=down_delay,
dup=down_duplicate,
per=down_loss,
unidirectional=True,
)
self.edge.asymmetric_link = core_pb2.Link(
node_one_id=link.node_two_id,
node_two_id=link.node_one_id,
interface_one=asym_interface_one,
interface_two=asym_interface_two,
options=options,
)
else:
link.options.unidirectional = False
self.edge.asymmetric_link = None
if self.app.core.is_runtime() and link.HasField("options"):
session_id = self.app.core.session_id
self.app.core.client.edit_link(
session_id,
link.node_one_id,
link.node_two_id,
link.options,
interface_one,
interface_two,
)
if self.edge.asymmetric_link:
self.app.core.client.edit_link(
session_id,
link.node_two_id,
link.node_one_id,
self.edge.asymmetric_link.options,
interface_one,
interface_two,
)
self.destroy()
def change_symmetry(self):
@ -212,6 +343,20 @@ class LinkConfiguration(Dialog):
:return: nothing
"""
width = self.app.canvas.itemcget(self.edge.id, "width")
# color = self.app.canvas.itemcget(self.edge.id, "fill")
self.width.set(width)
# self.color
color = self.app.canvas.itemcget(self.edge.id, "fill")
self.color.set(color)
link = self.edge.link
if link.HasField("options"):
self.bandwidth.set(str(link.options.bandwidth))
self.jitter.set(str(link.options.jitter))
self.duplicate.set(str(link.options.dup))
self.loss.set(str(link.options.per))
self.delay.set(str(link.options.delay))
if not self.is_symmetric:
asym_link = self.edge.asymmetric_link
self.down_bandwidth.set(str(asym_link.options.bandwidth))
self.down_jitter.set(str(asym_link.options.jitter))
self.down_duplicate.set(str(asym_link.options.dup))
self.down_loss.set(str(asym_link.options.per))
self.down_delay.set(str(asym_link.options.delay))

View file

@ -1,11 +1,14 @@
import logging
import tkinter as tk
from tkinter.font import Font
from coretk import themes
from coretk.dialogs.linkconfig import LinkConfiguration
from coretk.graph import tags
from coretk.nodeutils import NodeUtils
TEXT_DISTANCE = 0.30
class CanvasWirelessEdge:
def __init__(self, token, position, src, dst, canvas):
@ -46,14 +49,75 @@ class CanvasEdge:
self.id = self.canvas.create_line(
x1, y1, x2, y2, tags=tags.EDGE, width=self.width, fill="#ff0000"
)
self.text_src = None
self.text_dst = None
self.token = None
self.link_info = None
self.font = Font(size=8)
self.link = None
self.asymmetric_link = None
self.throughput = None
self.set_binding()
def set_binding(self):
self.canvas.tag_bind(self.id, "<ButtonRelease-3>", self.create_context)
def set_link(self, link):
self.link = link
self.draw_labels()
def get_coordinates(self):
x1, y1, x2, y2 = self.canvas.coords(self.id)
v1 = x2 - x1
v2 = y2 - y1
ux = TEXT_DISTANCE * v1
uy = TEXT_DISTANCE * v2
x1 = x1 + ux
y1 = y1 + uy
x2 = x2 - ux
y2 = y2 - uy
return x1, y1, x2, y2
def draw_labels(self):
x1, y1, x2, y2 = self.get_coordinates()
label_one = None
if self.link.HasField("interface_one"):
label_one = (
f"{self.link.interface_one.ip4}/{self.link.interface_one.ip4mask}\n"
f"{self.link.interface_one.ip6}/{self.link.interface_one.ip6mask}\n"
)
label_two = None
if self.link.HasField("interface_two"):
label_two = (
f"{self.link.interface_two.ip4}/{self.link.interface_two.ip4mask}\n"
f"{self.link.interface_two.ip6}/{self.link.interface_two.ip6mask}\n"
)
self.text_src = self.canvas.create_text(
x1,
y1,
text=label_one,
justify=tk.CENTER,
font=self.font,
tags=tags.LINK_INFO,
)
self.text_dst = self.canvas.create_text(
x2,
y2,
text=label_two,
justify=tk.CENTER,
font=self.font,
tags=tags.LINK_INFO,
)
def update_labels(self):
"""
Move edge labels based on current position.
:return: nothing
"""
x1, y1, x2, y2 = self.get_coordinates()
self.canvas.coords(self.text_src, x1, y1)
self.canvas.coords(self.text_dst, x2, y2)
def complete(self, dst):
self.dst = dst
self.token = tuple(sorted((self.src, self.dst)))
@ -93,9 +157,9 @@ class CanvasEdge:
def delete(self):
self.canvas.delete(self.id)
if self.link_info:
self.canvas.delete(self.link_info.id1)
self.canvas.delete(self.link_info.id2)
if self.link:
self.canvas.delete(self.text_src)
self.canvas.delete(self.text_dst)
def create_context(self, event):
logging.debug("create link context")

View file

@ -9,7 +9,7 @@ from coretk.dialogs.shapemod import ShapeDialog
from coretk.graph import tags
from coretk.graph.edges import CanvasEdge, CanvasWirelessEdge
from coretk.graph.enums import GraphMode, ScaleOption
from coretk.graph.linkinfo import LinkInfo, Throughput
from coretk.graph.linkinfo import Throughput
from coretk.graph.node import CanvasNode
from coretk.graph.shape import Shape
from coretk.graph.shapeutils import ShapeType, is_draw_shape, is_marker
@ -202,12 +202,12 @@ class CanvasGraph(tk.Canvas):
"""
# draw existing nodes
for core_node in session.nodes:
logging.info("drawing core node: %s", core_node)
# peer to peer node is not drawn on the GUI
if NodeUtils.is_ignore_node(core_node.type):
continue
# draw nodes on the canvas
logging.info("drawing core node: %s", core_node)
image = NodeUtils.node_icon(core_node.type, core_node.model)
if core_node.icon:
try:
@ -223,33 +223,42 @@ class CanvasGraph(tk.Canvas):
# draw existing links
for link in session.links:
logging.info("drawing link: %s", link)
canvas_node_one = self.core.canvas_nodes[link.node_one_id]
node_one = canvas_node_one.core_node
canvas_node_two = self.core.canvas_nodes[link.node_two_id]
node_two = canvas_node_two.core_node
token = tuple(sorted((canvas_node_one.id, canvas_node_two.id)))
if link.type == core_pb2.LinkType.WIRELESS:
self.add_wireless_edge(canvas_node_one, canvas_node_two)
else:
edge = CanvasEdge(
node_one.position.x,
node_one.position.y,
node_two.position.x,
node_two.position.y,
canvas_node_one.id,
self,
)
edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id)))
edge.dst = canvas_node_two.id
edge.check_wireless()
canvas_node_one.edges.add(edge)
canvas_node_two.edges.add(edge)
self.edges[edge.token] = edge
self.core.links[edge.token] = link
edge.link_info = LinkInfo(self, edge, link)
if link.HasField("interface_one"):
canvas_node_one.interfaces.append(link.interface_one)
if link.HasField("interface_two"):
canvas_node_two.interfaces.append(link.interface_two)
if token not in self.edges:
edge = CanvasEdge(
node_one.position.x,
node_one.position.y,
node_two.position.x,
node_two.position.y,
canvas_node_one.id,
self,
)
edge.token = token
edge.dst = canvas_node_two.id
edge.set_link(link)
edge.check_wireless()
canvas_node_one.edges.add(edge)
canvas_node_two.edges.add(edge)
self.edges[edge.token] = edge
self.core.links[edge.token] = edge
if link.HasField("interface_one"):
canvas_node_one.interfaces.append(link.interface_one)
if link.HasField("interface_two"):
canvas_node_two.interfaces.append(link.interface_two)
elif link.options.unidirectional:
edge = self.edges[token]
edge.asymmetric_link = link
else:
logging.error("duplicate link received: %s", link)
# raise the nodes so they on top of the links
self.tag_raise(tags.NODE)
@ -373,8 +382,7 @@ class CanvasGraph(tk.Canvas):
node_src.edges.add(edge)
node_dst = self.nodes[edge.dst]
node_dst.edges.add(edge)
link = self.core.create_link(edge, node_src, node_dst)
edge.link_info = LinkInfo(self, edge, link)
self.core.create_link(edge, node_src, node_dst)
def select_object(self, object_id, choose_multiple=False):
"""
@ -819,7 +827,7 @@ class CanvasGraph(tk.Canvas):
:param CanvasNode dest: destination node
:return: nothing
"""
if tuple([source.id, dest.id]) not in self.edges:
if (source.id, dest.id) not in self.edges:
pos0 = source.core_node.position
x0 = pos0.x
y0 = pos0.y
@ -828,5 +836,4 @@ class CanvasGraph(tk.Canvas):
self.edges[edge.token] = edge
self.nodes[source.id].edges.add(edge)
self.nodes[dest.id].edges.add(edge)
link = self.core.create_link(edge, source, dest)
edge.link_info = LinkInfo(self, edge, link)
self.core.create_link(edge, source, dest)

View file

@ -1,83 +1,8 @@
"""
Link information, such as IPv4, IPv6 and throughput drawn in the canvas
"""
import tkinter as tk
from tkinter import font
from core.api.grpc import core_pb2
from coretk.graph import tags
TEXT_DISTANCE = 0.30
class LinkInfo:
def __init__(self, canvas, edge, link):
"""
create an instance of LinkInfo object
:param coretk.graph.Graph canvas: canvas object
:param coretk.graph.CanvasEdge edge: canvas edge onject
:param link: core link to draw info for
"""
self.canvas = canvas
self.edge = edge
self.link = link
self.id1 = None
self.id2 = None
self.font = font.Font(size=8)
self.draw_labels()
def get_coordinates(self):
x1, y1, x2, y2 = self.canvas.coords(self.edge.id)
v1 = x2 - x1
v2 = y2 - y1
ux = TEXT_DISTANCE * v1
uy = TEXT_DISTANCE * v2
x1 = x1 + ux
y1 = y1 + uy
x2 = x2 - ux
y2 = y2 - uy
return x1, y1, x2, y2
def draw_labels(self):
x1, y1, x2, y2 = self.get_coordinates()
label_one = None
if self.link.HasField("interface_one"):
label_one = (
f"{self.link.interface_one.ip4}/{self.link.interface_one.ip4mask}\n"
f"{self.link.interface_one.ip6}/{self.link.interface_one.ip6mask}\n"
)
label_two = None
if self.link.HasField("interface_two"):
label_two = (
f"{self.link.interface_two.ip4}/{self.link.interface_two.ip4mask}\n"
f"{self.link.interface_two.ip6}/{self.link.interface_two.ip6mask}\n"
)
self.id1 = self.canvas.create_text(
x1,
y1,
text=label_one,
justify=tk.CENTER,
font=self.font,
tags=tags.LINK_INFO,
)
self.id2 = self.canvas.create_text(
x2,
y2,
text=label_two,
justify=tk.CENTER,
font=self.font,
tags=tags.LINK_INFO,
)
def recalculate_info(self):
"""
move the node info when the canvas node move
:return: nothing
"""
x1, y1, x2, y2 = self.get_coordinates()
self.canvas.coords(self.id1, x1, y1)
self.canvas.coords(self.id2, x2, y2)
class Throughput:

View file

@ -129,7 +129,7 @@ class CanvasNode:
else:
self.canvas.coords(edge.id, x1, y1, x, y)
self.canvas.throughput_draw.move(edge)
edge.link_info.recalculate_info()
edge.update_labels()
for edge in self.wireless_edges:
x1, y1, x2, y2 = self.canvas.coords(edge.id)

View file

@ -161,6 +161,7 @@ class CoreGrpcClient:
mobility_configs=None,
service_configs=None,
service_file_configs=None,
asymmetric_links=None,
):
"""
Start a session.
@ -176,6 +177,7 @@ class CoreGrpcClient:
:param list mobility_configs: node mobility configurations
:param list service_configs: node service configurations
:param list service_file_configs: node service file configurations
:param list asymmetric_links: asymmetric links to edit
:return: start session response
:rtype: core_pb2.StartSessionResponse
"""
@ -191,6 +193,7 @@ class CoreGrpcClient:
mobility_configs=mobility_configs,
service_configs=service_configs,
service_file_configs=service_file_configs,
asymmetric_links=asymmetric_links,
)
return self.stub.StartSession(request)

View file

@ -128,7 +128,7 @@ def create_nodes(session, node_protos):
def create_links(session, link_protos):
"""
Create nodes using a thread pool and wait for completion.
Create links using a thread pool and wait for completion.
:param core.emulator.session.Session session: session to create nodes in
:param list[core_pb2.Link] link_protos: link proto messages
@ -149,6 +149,29 @@ def create_links(session, link_protos):
return results, exceptions
def edit_links(session, link_protos):
"""
Edit links using a thread pool and wait for completion.
:param core.emulator.session.Session session: session to create nodes in
:param list[core_pb2.Link] link_protos: link proto messages
:return: results and exceptions for created links
:rtype: tuple
"""
funcs = []
for link_proto in link_protos:
node_one_id = link_proto.node_one_id
node_two_id = link_proto.node_two_id
interface_one, interface_two, options = add_link_data(link_proto)
args = (node_one_id, node_two_id, interface_one.id, interface_two.id, options)
funcs.append((session.update_link, args, {}))
start = time.monotonic()
results, exceptions = utils.threadpool(funcs)
total = time.monotonic() - start
logging.debug("grpc edit links time: %s", total)
return results, exceptions
def convert_value(value):
"""
Convert value into string.

View file

@ -158,6 +158,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
# create links
grpcutils.create_links(session, request.links)
# asymmetric links
grpcutils.edit_links(session, request.asymmetric_links)
# set to instantiation and start
session.set_state(EventTypes.INSTANTIATION_STATE)
session.instantiate()

View file

@ -1053,6 +1053,7 @@ class CoreNetworkBase(NodeBase):
message_type=0,
node1_id=linked_node.id,
node2_id=self.id,
link_type=self.linktype,
unidirectional=1,
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),

View file

@ -965,6 +965,7 @@ class PtpNet(CoreNetwork):
if unidirectional:
link_data = LinkData(
message_type=0,
link_type=self.linktype,
node1_id=if2.node.id,
node2_id=if1.node.id,
delay=if2.getparam("delay"),

View file

@ -150,6 +150,7 @@ message StartSessionRequest {
repeated MobilityConfig mobility_configs = 9;
repeated ServiceConfig service_configs = 10;
repeated ServiceFileConfig service_file_configs = 11;
repeated Link asymmetric_links = 12;
}
message StartSessionResponse {