daemon: added link option to configure buffer, added support in pygui to allow configuring buffer
This commit is contained in:
parent
d95c2ec05f
commit
a35e91aeba
8 changed files with 68 additions and 5 deletions
|
@ -128,6 +128,7 @@ def add_link_data(
|
||||||
options.mer = options_proto.mer
|
options.mer = options_proto.mer
|
||||||
options.burst = options_proto.burst
|
options.burst = options_proto.burst
|
||||||
options.mburst = options_proto.mburst
|
options.mburst = options_proto.mburst
|
||||||
|
options.buffer = options_proto.buffer
|
||||||
options.unidirectional = options_proto.unidirectional
|
options.unidirectional = options_proto.unidirectional
|
||||||
options.key = options_proto.key
|
options.key = options_proto.key
|
||||||
return iface1_data, iface2_data, options, link_type
|
return iface1_data, iface2_data, options, link_type
|
||||||
|
@ -329,6 +330,7 @@ def convert_link_options(options_data: LinkOptions) -> core_pb2.LinkOptions:
|
||||||
burst=options_data.burst,
|
burst=options_data.burst,
|
||||||
delay=options_data.delay,
|
delay=options_data.delay,
|
||||||
dup=options_data.dup,
|
dup=options_data.dup,
|
||||||
|
buffer=options_data.buffer,
|
||||||
unidirectional=options_data.unidirectional,
|
unidirectional=options_data.unidirectional,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -972,6 +972,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
mburst=options_proto.mburst,
|
mburst=options_proto.mburst,
|
||||||
unidirectional=options_proto.unidirectional,
|
unidirectional=options_proto.unidirectional,
|
||||||
key=options_proto.key,
|
key=options_proto.key,
|
||||||
|
buffer=options_proto.buffer,
|
||||||
)
|
)
|
||||||
session.update_link(node1_id, node2_id, iface1_id, iface2_id, options)
|
session.update_link(node1_id, node2_id, iface1_id, iface2_id, options)
|
||||||
iface1 = InterfaceData(id=iface1_id)
|
iface1 = InterfaceData(id=iface1_id)
|
||||||
|
|
|
@ -457,6 +457,7 @@ class LinkOptions:
|
||||||
delay: int = 0
|
delay: int = 0
|
||||||
dup: int = 0
|
dup: int = 0
|
||||||
unidirectional: bool = False
|
unidirectional: bool = False
|
||||||
|
buffer: int = 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_proto(cls, proto: core_pb2.LinkOptions) -> "LinkOptions":
|
def from_proto(cls, proto: core_pb2.LinkOptions) -> "LinkOptions":
|
||||||
|
@ -471,6 +472,7 @@ class LinkOptions:
|
||||||
delay=proto.delay,
|
delay=proto.delay,
|
||||||
dup=proto.dup,
|
dup=proto.dup,
|
||||||
unidirectional=proto.unidirectional,
|
unidirectional=proto.unidirectional,
|
||||||
|
buffer=proto.buffer,
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_proto(self) -> core_pb2.LinkOptions:
|
def to_proto(self) -> core_pb2.LinkOptions:
|
||||||
|
@ -485,6 +487,7 @@ class LinkOptions:
|
||||||
delay=self.delay,
|
delay=self.delay,
|
||||||
dup=self.dup,
|
dup=self.dup,
|
||||||
unidirectional=self.unidirectional,
|
unidirectional=self.unidirectional,
|
||||||
|
buffer=self.buffer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,7 @@ class LinkOptions:
|
||||||
mburst: int = None
|
mburst: int = None
|
||||||
unidirectional: int = None
|
unidirectional: int = None
|
||||||
key: int = None
|
key: int = None
|
||||||
|
buffer: int = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -49,12 +49,14 @@ class LinkConfigurationDialog(Dialog):
|
||||||
self.jitter: tk.StringVar = tk.StringVar()
|
self.jitter: tk.StringVar = tk.StringVar()
|
||||||
self.loss: tk.StringVar = tk.StringVar()
|
self.loss: tk.StringVar = tk.StringVar()
|
||||||
self.duplicate: tk.StringVar = tk.StringVar()
|
self.duplicate: tk.StringVar = tk.StringVar()
|
||||||
|
self.buffer: tk.StringVar = tk.StringVar()
|
||||||
|
|
||||||
self.down_bandwidth: tk.StringVar = tk.StringVar()
|
self.down_bandwidth: tk.StringVar = tk.StringVar()
|
||||||
self.down_delay: tk.StringVar = tk.StringVar()
|
self.down_delay: tk.StringVar = tk.StringVar()
|
||||||
self.down_jitter: tk.StringVar = tk.StringVar()
|
self.down_jitter: tk.StringVar = tk.StringVar()
|
||||||
self.down_loss: tk.StringVar = tk.StringVar()
|
self.down_loss: tk.StringVar = tk.StringVar()
|
||||||
self.down_duplicate: tk.StringVar = tk.StringVar()
|
self.down_duplicate: tk.StringVar = tk.StringVar()
|
||||||
|
self.down_buffer: tk.StringVar = tk.StringVar()
|
||||||
|
|
||||||
self.color: tk.StringVar = tk.StringVar(value=self.edge.color)
|
self.color: tk.StringVar = tk.StringVar(value=self.edge.color)
|
||||||
self.color_button: Optional[tk.Button] = None
|
self.color_button: Optional[tk.Button] = None
|
||||||
|
@ -187,6 +189,19 @@ class LinkConfigurationDialog(Dialog):
|
||||||
entry.grid(row=row, column=2, sticky=tk.EW, pady=PADY)
|
entry.grid(row=row, column=2, sticky=tk.EW, pady=PADY)
|
||||||
row = row + 1
|
row = row + 1
|
||||||
|
|
||||||
|
label = ttk.Label(frame, text="Buffer (Packets)")
|
||||||
|
label.grid(row=row, column=0, sticky=tk.EW)
|
||||||
|
entry = validation.PositiveIntEntry(
|
||||||
|
frame, empty_enabled=False, textvariable=self.buffer
|
||||||
|
)
|
||||||
|
entry.grid(row=row, column=1, sticky=tk.EW, pady=PADY)
|
||||||
|
if not self.is_symmetric:
|
||||||
|
entry = validation.PositiveIntEntry(
|
||||||
|
frame, empty_enabled=False, textvariable=self.down_buffer
|
||||||
|
)
|
||||||
|
entry.grid(row=row, column=2, sticky=tk.EW, pady=PADY)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
label = ttk.Label(frame, text="Color")
|
label = ttk.Label(frame, text="Color")
|
||||||
label.grid(row=row, column=0, sticky=tk.EW)
|
label.grid(row=row, column=0, sticky=tk.EW)
|
||||||
self.color_button = tk.Button(
|
self.color_button = tk.Button(
|
||||||
|
@ -224,9 +239,15 @@ class LinkConfigurationDialog(Dialog):
|
||||||
jitter = get_int(self.jitter)
|
jitter = get_int(self.jitter)
|
||||||
delay = get_int(self.delay)
|
delay = get_int(self.delay)
|
||||||
duplicate = get_int(self.duplicate)
|
duplicate = get_int(self.duplicate)
|
||||||
|
buffer = get_int(self.buffer)
|
||||||
loss = get_float(self.loss)
|
loss = get_float(self.loss)
|
||||||
options = LinkOptions(
|
options = LinkOptions(
|
||||||
bandwidth=bandwidth, jitter=jitter, delay=delay, dup=duplicate, loss=loss
|
bandwidth=bandwidth,
|
||||||
|
jitter=jitter,
|
||||||
|
delay=delay,
|
||||||
|
dup=duplicate,
|
||||||
|
loss=loss,
|
||||||
|
buffer=buffer,
|
||||||
)
|
)
|
||||||
link.options = options
|
link.options = options
|
||||||
iface1_id = link.iface1.id if link.iface1 else None
|
iface1_id = link.iface1.id if link.iface1 else None
|
||||||
|
@ -243,6 +264,7 @@ class LinkConfigurationDialog(Dialog):
|
||||||
down_jitter = get_int(self.down_jitter)
|
down_jitter = get_int(self.down_jitter)
|
||||||
down_delay = get_int(self.down_delay)
|
down_delay = get_int(self.down_delay)
|
||||||
down_duplicate = get_int(self.down_duplicate)
|
down_duplicate = get_int(self.down_duplicate)
|
||||||
|
down_buffer = get_int(self.down_buffer)
|
||||||
down_loss = get_float(self.down_loss)
|
down_loss = get_float(self.down_loss)
|
||||||
options = LinkOptions(
|
options = LinkOptions(
|
||||||
bandwidth=down_bandwidth,
|
bandwidth=down_bandwidth,
|
||||||
|
@ -250,6 +272,7 @@ class LinkConfigurationDialog(Dialog):
|
||||||
delay=down_delay,
|
delay=down_delay,
|
||||||
dup=down_duplicate,
|
dup=down_duplicate,
|
||||||
loss=down_loss,
|
loss=down_loss,
|
||||||
|
buffer=down_buffer,
|
||||||
unidirectional=True,
|
unidirectional=True,
|
||||||
)
|
)
|
||||||
self.edge.asymmetric_link = Link(
|
self.edge.asymmetric_link = Link(
|
||||||
|
@ -304,6 +327,7 @@ class LinkConfigurationDialog(Dialog):
|
||||||
self.duplicate.set(str(link.options.dup))
|
self.duplicate.set(str(link.options.dup))
|
||||||
self.loss.set(str(link.options.loss))
|
self.loss.set(str(link.options.loss))
|
||||||
self.delay.set(str(link.options.delay))
|
self.delay.set(str(link.options.delay))
|
||||||
|
self.buffer.set(str(link.options.buffer))
|
||||||
if not self.is_symmetric:
|
if not self.is_symmetric:
|
||||||
asym_link = self.edge.asymmetric_link
|
asym_link = self.edge.asymmetric_link
|
||||||
self.down_bandwidth.set(str(asym_link.options.bandwidth))
|
self.down_bandwidth.set(str(asym_link.options.bandwidth))
|
||||||
|
@ -311,3 +335,4 @@ class LinkConfigurationDialog(Dialog):
|
||||||
self.down_duplicate.set(str(asym_link.options.dup))
|
self.down_duplicate.set(str(asym_link.options.dup))
|
||||||
self.down_loss.set(str(asym_link.options.loss))
|
self.down_loss.set(str(asym_link.options.loss))
|
||||||
self.down_delay.set(str(asym_link.options.delay))
|
self.down_delay.set(str(asym_link.options.delay))
|
||||||
|
self.down_buffer.set(str(asym_link.options.buffer))
|
||||||
|
|
|
@ -456,6 +456,7 @@ class CoreNetwork(CoreNetworkBase):
|
||||||
iface.setparam("loss", options.loss),
|
iface.setparam("loss", options.loss),
|
||||||
iface.setparam("duplicate", options.dup),
|
iface.setparam("duplicate", options.dup),
|
||||||
iface.setparam("jitter", options.jitter),
|
iface.setparam("jitter", options.jitter),
|
||||||
|
iface.setparam("buffer", options.buffer),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if not changed:
|
if not changed:
|
||||||
|
@ -470,6 +471,7 @@ class CoreNetwork(CoreNetworkBase):
|
||||||
options.loss is None or options.loss <= 0,
|
options.loss is None or options.loss <= 0,
|
||||||
options.dup is None or options.dup <= 0,
|
options.dup is None or options.dup <= 0,
|
||||||
options.bandwidth is None or options.bandwidth <= 0,
|
options.bandwidth is None or options.bandwidth <= 0,
|
||||||
|
options.buffer is None or options.buffer <= 0,
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
if not iface.getparam("has_netem"):
|
if not iface.getparam("has_netem"):
|
||||||
|
@ -483,7 +485,9 @@ class CoreNetwork(CoreNetworkBase):
|
||||||
if options.bandwidth is not None:
|
if options.bandwidth is not None:
|
||||||
limit = 1000
|
limit = 1000
|
||||||
bw = options.bandwidth / 1000
|
bw = options.bandwidth / 1000
|
||||||
if options.delay and options.bandwidth:
|
if options.buffer is not None and options.buffer > 0:
|
||||||
|
limit = options.buffer
|
||||||
|
elif options.delay and options.bandwidth:
|
||||||
delay = options.delay / 1000
|
delay = options.delay / 1000
|
||||||
limit = max(2, math.ceil((2 * bw * delay) / (8 * iface.mtu)))
|
limit = max(2, math.ceil((2 * bw * delay) / (8 * iface.mtu)))
|
||||||
netem += f" rate {bw}kbit"
|
netem += f" rate {bw}kbit"
|
||||||
|
|
|
@ -777,6 +777,7 @@ message LinkOptions {
|
||||||
int64 delay = 8;
|
int64 delay = 8;
|
||||||
int32 dup = 9;
|
int32 dup = 9;
|
||||||
bool unidirectional = 10;
|
bool unidirectional = 10;
|
||||||
|
int32 buffer = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Interface {
|
message Interface {
|
||||||
|
|
|
@ -83,6 +83,7 @@ class TestLinks:
|
||||||
loss = 25
|
loss = 25
|
||||||
dup = 25
|
dup = 25
|
||||||
jitter = 10
|
jitter = 10
|
||||||
|
buffer = 100
|
||||||
node1 = session.add_node(CoreNode)
|
node1 = session.add_node(CoreNode)
|
||||||
node2 = session.add_node(SwitchNode)
|
node2 = session.add_node(SwitchNode)
|
||||||
iface1_data = ip_prefixes.create_iface(node1)
|
iface1_data = ip_prefixes.create_iface(node1)
|
||||||
|
@ -93,10 +94,16 @@ class TestLinks:
|
||||||
assert iface1.getparam("loss") != loss
|
assert iface1.getparam("loss") != loss
|
||||||
assert iface1.getparam("duplicate") != dup
|
assert iface1.getparam("duplicate") != dup
|
||||||
assert iface1.getparam("jitter") != jitter
|
assert iface1.getparam("jitter") != jitter
|
||||||
|
assert iface1.getparam("buffer") != buffer
|
||||||
|
|
||||||
# when
|
# when
|
||||||
options = LinkOptions(
|
options = LinkOptions(
|
||||||
delay=delay, bandwidth=bandwidth, loss=loss, dup=dup, jitter=jitter
|
delay=delay,
|
||||||
|
bandwidth=bandwidth,
|
||||||
|
loss=loss,
|
||||||
|
dup=dup,
|
||||||
|
jitter=jitter,
|
||||||
|
buffer=buffer,
|
||||||
)
|
)
|
||||||
session.update_link(
|
session.update_link(
|
||||||
node1.id, node2.id, iface1_id=iface1_data.id, options=options
|
node1.id, node2.id, iface1_id=iface1_data.id, options=options
|
||||||
|
@ -108,6 +115,7 @@ class TestLinks:
|
||||||
assert iface1.getparam("loss") == loss
|
assert iface1.getparam("loss") == loss
|
||||||
assert iface1.getparam("duplicate") == dup
|
assert iface1.getparam("duplicate") == dup
|
||||||
assert iface1.getparam("jitter") == jitter
|
assert iface1.getparam("jitter") == jitter
|
||||||
|
assert iface1.getparam("buffer") == buffer
|
||||||
|
|
||||||
def test_update_net_to_node(self, session: Session, ip_prefixes: IpPrefixes):
|
def test_update_net_to_node(self, session: Session, ip_prefixes: IpPrefixes):
|
||||||
# given
|
# given
|
||||||
|
@ -116,6 +124,7 @@ class TestLinks:
|
||||||
loss = 25
|
loss = 25
|
||||||
dup = 25
|
dup = 25
|
||||||
jitter = 10
|
jitter = 10
|
||||||
|
buffer = 100
|
||||||
node1 = session.add_node(SwitchNode)
|
node1 = session.add_node(SwitchNode)
|
||||||
node2 = session.add_node(CoreNode)
|
node2 = session.add_node(CoreNode)
|
||||||
iface2_data = ip_prefixes.create_iface(node2)
|
iface2_data = ip_prefixes.create_iface(node2)
|
||||||
|
@ -126,10 +135,16 @@ class TestLinks:
|
||||||
assert iface2.getparam("loss") != loss
|
assert iface2.getparam("loss") != loss
|
||||||
assert iface2.getparam("duplicate") != dup
|
assert iface2.getparam("duplicate") != dup
|
||||||
assert iface2.getparam("jitter") != jitter
|
assert iface2.getparam("jitter") != jitter
|
||||||
|
assert iface2.getparam("buffer") != buffer
|
||||||
|
|
||||||
# when
|
# when
|
||||||
options = LinkOptions(
|
options = LinkOptions(
|
||||||
delay=delay, bandwidth=bandwidth, loss=loss, dup=dup, jitter=jitter
|
delay=delay,
|
||||||
|
bandwidth=bandwidth,
|
||||||
|
loss=loss,
|
||||||
|
dup=dup,
|
||||||
|
jitter=jitter,
|
||||||
|
buffer=buffer,
|
||||||
)
|
)
|
||||||
session.update_link(
|
session.update_link(
|
||||||
node1.id, node2.id, iface2_id=iface2_data.id, options=options
|
node1.id, node2.id, iface2_id=iface2_data.id, options=options
|
||||||
|
@ -141,6 +156,7 @@ class TestLinks:
|
||||||
assert iface2.getparam("loss") == loss
|
assert iface2.getparam("loss") == loss
|
||||||
assert iface2.getparam("duplicate") == dup
|
assert iface2.getparam("duplicate") == dup
|
||||||
assert iface2.getparam("jitter") == jitter
|
assert iface2.getparam("jitter") == jitter
|
||||||
|
assert iface2.getparam("buffer") == buffer
|
||||||
|
|
||||||
def test_update_ptp(self, session: Session, ip_prefixes: IpPrefixes):
|
def test_update_ptp(self, session: Session, ip_prefixes: IpPrefixes):
|
||||||
# given
|
# given
|
||||||
|
@ -149,6 +165,7 @@ class TestLinks:
|
||||||
loss = 25
|
loss = 25
|
||||||
dup = 25
|
dup = 25
|
||||||
jitter = 10
|
jitter = 10
|
||||||
|
buffer = 100
|
||||||
node1 = session.add_node(CoreNode)
|
node1 = session.add_node(CoreNode)
|
||||||
node2 = session.add_node(CoreNode)
|
node2 = session.add_node(CoreNode)
|
||||||
iface1_data = ip_prefixes.create_iface(node1)
|
iface1_data = ip_prefixes.create_iface(node1)
|
||||||
|
@ -161,15 +178,22 @@ class TestLinks:
|
||||||
assert iface1.getparam("loss") != loss
|
assert iface1.getparam("loss") != loss
|
||||||
assert iface1.getparam("duplicate") != dup
|
assert iface1.getparam("duplicate") != dup
|
||||||
assert iface1.getparam("jitter") != jitter
|
assert iface1.getparam("jitter") != jitter
|
||||||
|
assert iface1.getparam("buffer") != buffer
|
||||||
assert iface2.getparam("delay") != delay
|
assert iface2.getparam("delay") != delay
|
||||||
assert iface2.getparam("bw") != bandwidth
|
assert iface2.getparam("bw") != bandwidth
|
||||||
assert iface2.getparam("loss") != loss
|
assert iface2.getparam("loss") != loss
|
||||||
assert iface2.getparam("duplicate") != dup
|
assert iface2.getparam("duplicate") != dup
|
||||||
assert iface2.getparam("jitter") != jitter
|
assert iface2.getparam("jitter") != jitter
|
||||||
|
assert iface2.getparam("buffer") != buffer
|
||||||
|
|
||||||
# when
|
# when
|
||||||
options = LinkOptions(
|
options = LinkOptions(
|
||||||
delay=delay, bandwidth=bandwidth, loss=loss, dup=dup, jitter=jitter
|
delay=delay,
|
||||||
|
bandwidth=bandwidth,
|
||||||
|
loss=loss,
|
||||||
|
dup=dup,
|
||||||
|
jitter=jitter,
|
||||||
|
buffer=buffer,
|
||||||
)
|
)
|
||||||
session.update_link(node1.id, node2.id, iface1_data.id, iface2_data.id, options)
|
session.update_link(node1.id, node2.id, iface1_data.id, iface2_data.id, options)
|
||||||
|
|
||||||
|
@ -179,11 +203,13 @@ class TestLinks:
|
||||||
assert iface1.getparam("loss") == loss
|
assert iface1.getparam("loss") == loss
|
||||||
assert iface1.getparam("duplicate") == dup
|
assert iface1.getparam("duplicate") == dup
|
||||||
assert iface1.getparam("jitter") == jitter
|
assert iface1.getparam("jitter") == jitter
|
||||||
|
assert iface1.getparam("buffer") == buffer
|
||||||
assert iface2.getparam("delay") == delay
|
assert iface2.getparam("delay") == delay
|
||||||
assert iface2.getparam("bw") == bandwidth
|
assert iface2.getparam("bw") == bandwidth
|
||||||
assert iface2.getparam("loss") == loss
|
assert iface2.getparam("loss") == loss
|
||||||
assert iface2.getparam("duplicate") == dup
|
assert iface2.getparam("duplicate") == dup
|
||||||
assert iface2.getparam("jitter") == jitter
|
assert iface2.getparam("jitter") == jitter
|
||||||
|
assert iface2.getparam("buffer") == buffer
|
||||||
|
|
||||||
def test_delete_ptp(self, session: Session, ip_prefixes: IpPrefixes):
|
def test_delete_ptp(self, session: Session, ip_prefixes: IpPrefixes):
|
||||||
# given
|
# given
|
||||||
|
|
Loading…
Reference in a new issue