Merge pull request #529 from coreemu/enhancement/link-buffer-size
updates for link configuration to calculate a limit when bandwidth/delay are present
This commit is contained in:
commit
d95c2ec05f
9 changed files with 65 additions and 78 deletions
|
@ -788,14 +788,18 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
options = LinkOptions()
|
options = LinkOptions()
|
||||||
options.delay = message.get_tlv(LinkTlvs.DELAY.value)
|
options.delay = message.get_tlv(LinkTlvs.DELAY.value)
|
||||||
options.bandwidth = message.get_tlv(LinkTlvs.BANDWIDTH.value)
|
options.bandwidth = message.get_tlv(LinkTlvs.BANDWIDTH.value)
|
||||||
options.loss = message.get_tlv(LinkTlvs.LOSS.value)
|
|
||||||
options.dup = message.get_tlv(LinkTlvs.DUP.value)
|
|
||||||
options.jitter = message.get_tlv(LinkTlvs.JITTER.value)
|
options.jitter = message.get_tlv(LinkTlvs.JITTER.value)
|
||||||
options.mer = message.get_tlv(LinkTlvs.MER.value)
|
options.mer = message.get_tlv(LinkTlvs.MER.value)
|
||||||
options.burst = message.get_tlv(LinkTlvs.BURST.value)
|
options.burst = message.get_tlv(LinkTlvs.BURST.value)
|
||||||
options.mburst = message.get_tlv(LinkTlvs.MBURST.value)
|
options.mburst = message.get_tlv(LinkTlvs.MBURST.value)
|
||||||
options.unidirectional = message.get_tlv(LinkTlvs.UNIDIRECTIONAL.value)
|
options.unidirectional = message.get_tlv(LinkTlvs.UNIDIRECTIONAL.value)
|
||||||
options.key = message.get_tlv(LinkTlvs.KEY.value)
|
options.key = message.get_tlv(LinkTlvs.KEY.value)
|
||||||
|
loss = message.get_tlv(LinkTlvs.LOSS.value)
|
||||||
|
dup = message.get_tlv(LinkTlvs.DUP.value)
|
||||||
|
if loss is not None:
|
||||||
|
options.loss = float(loss)
|
||||||
|
if dup is not None:
|
||||||
|
options.dup = int(dup)
|
||||||
|
|
||||||
if message.flags & MessageFlags.ADD.value:
|
if message.flags & MessageFlags.ADD.value:
|
||||||
self.session.add_link(
|
self.session.add_link(
|
||||||
|
|
|
@ -5,7 +5,7 @@ from core.config import Configuration
|
||||||
from core.configservice.base import ConfigService, ConfigServiceMode
|
from core.configservice.base import ConfigService, ConfigServiceMode
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.nodes.base import CoreNodeBase
|
from core.nodes.base import CoreNodeBase
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.network import WlanNode
|
from core.nodes.network import WlanNode
|
||||||
|
|
||||||
GROUP: str = "FRR"
|
GROUP: str = "FRR"
|
||||||
|
@ -18,7 +18,7 @@ def has_mtu_mismatch(iface: CoreInterface) -> bool:
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
if iface.mtu != 1500:
|
if iface.mtu != DEFAULT_MTU:
|
||||||
return True
|
return True
|
||||||
if not iface.net:
|
if not iface.net:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -6,7 +6,7 @@ from core.config import Configuration
|
||||||
from core.configservice.base import ConfigService, ConfigServiceMode
|
from core.configservice.base import ConfigService, ConfigServiceMode
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.nodes.base import CoreNodeBase
|
from core.nodes.base import CoreNodeBase
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.network import WlanNode
|
from core.nodes.network import WlanNode
|
||||||
|
|
||||||
GROUP: str = "Quagga"
|
GROUP: str = "Quagga"
|
||||||
|
@ -19,7 +19,7 @@ def has_mtu_mismatch(iface: CoreInterface) -> bool:
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
if iface.mtu != 1500:
|
if iface.mtu != DEFAULT_MTU:
|
||||||
return True
|
return True
|
||||||
if not iface.net:
|
if not iface.net:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -30,8 +30,6 @@ if TYPE_CHECKING:
|
||||||
CoreServices = List[Union[CoreService, Type[CoreService]]]
|
CoreServices = List[Union[CoreService, Type[CoreService]]]
|
||||||
ConfigServiceType = Type[ConfigService]
|
ConfigServiceType = Type[ConfigService]
|
||||||
|
|
||||||
_DEFAULT_MTU = 1500
|
|
||||||
|
|
||||||
|
|
||||||
class NodeBase(abc.ABC):
|
class NodeBase(abc.ABC):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -19,6 +19,8 @@ if TYPE_CHECKING:
|
||||||
from core.emulator.session import Session
|
from core.emulator.session import Session
|
||||||
from core.nodes.base import CoreNetworkBase, CoreNode
|
from core.nodes.base import CoreNetworkBase, CoreNode
|
||||||
|
|
||||||
|
DEFAULT_MTU: int = 1500
|
||||||
|
|
||||||
|
|
||||||
class CoreInterface:
|
class CoreInterface:
|
||||||
"""
|
"""
|
||||||
|
@ -338,7 +340,7 @@ class Veth(CoreInterface):
|
||||||
node: "CoreNode",
|
node: "CoreNode",
|
||||||
name: str,
|
name: str,
|
||||||
localname: str,
|
localname: str,
|
||||||
mtu: int = 1500,
|
mtu: int = DEFAULT_MTU,
|
||||||
server: "DistributedServer" = None,
|
server: "DistributedServer" = None,
|
||||||
start: bool = True,
|
start: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -403,7 +405,7 @@ class TunTap(CoreInterface):
|
||||||
node: "CoreNode",
|
node: "CoreNode",
|
||||||
name: str,
|
name: str,
|
||||||
localname: str,
|
localname: str,
|
||||||
mtu: int = 1500,
|
mtu: int = DEFAULT_MTU,
|
||||||
server: "DistributedServer" = None,
|
server: "DistributedServer" = None,
|
||||||
start: bool = True,
|
start: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -3,6 +3,7 @@ Defines network nodes used within core.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type
|
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type
|
||||||
|
@ -447,77 +448,59 @@ class CoreNetwork(CoreNetworkBase):
|
||||||
:param iface2: interface two
|
:param iface2: interface two
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
devname = iface.localname
|
# determine if any settings have changed
|
||||||
tc = f"{TC} qdisc replace dev {devname}"
|
changed = any(
|
||||||
parent = "root"
|
[
|
||||||
changed = False
|
iface.setparam("bw", options.bandwidth),
|
||||||
bw = options.bandwidth
|
iface.setparam("delay", options.delay),
|
||||||
if iface.setparam("bw", bw):
|
iface.setparam("loss", options.loss),
|
||||||
# from tc-tbf(8): minimum value for burst is rate / kernel_hz
|
iface.setparam("duplicate", options.dup),
|
||||||
burst = max(2 * iface.mtu, int(bw / 1000))
|
iface.setparam("jitter", options.jitter),
|
||||||
# max IP payload
|
]
|
||||||
limit = 0xFFFF
|
)
|
||||||
tbf = f"tbf rate {bw} burst {burst} limit {limit}"
|
|
||||||
if bw > 0:
|
|
||||||
if self.up:
|
|
||||||
cmd = f"{tc} {parent} handle 1: {tbf}"
|
|
||||||
iface.host_cmd(cmd)
|
|
||||||
iface.setparam("has_tbf", True)
|
|
||||||
changed = True
|
|
||||||
elif iface.getparam("has_tbf") and bw <= 0:
|
|
||||||
if self.up:
|
|
||||||
cmd = f"{TC} qdisc delete dev {devname} {parent}"
|
|
||||||
iface.host_cmd(cmd)
|
|
||||||
iface.setparam("has_tbf", False)
|
|
||||||
# removing the parent removes the child
|
|
||||||
iface.setparam("has_netem", False)
|
|
||||||
changed = True
|
|
||||||
if iface.getparam("has_tbf"):
|
|
||||||
parent = "parent 1:1"
|
|
||||||
netem = "netem"
|
|
||||||
delay = options.delay
|
|
||||||
changed = max(changed, iface.setparam("delay", delay))
|
|
||||||
loss = options.loss
|
|
||||||
if loss is not None:
|
|
||||||
loss = float(loss)
|
|
||||||
changed = max(changed, iface.setparam("loss", loss))
|
|
||||||
duplicate = options.dup
|
|
||||||
if duplicate is not None:
|
|
||||||
duplicate = int(duplicate)
|
|
||||||
changed = max(changed, iface.setparam("duplicate", duplicate))
|
|
||||||
jitter = options.jitter
|
|
||||||
changed = max(changed, iface.setparam("jitter", jitter))
|
|
||||||
if not changed:
|
if not changed:
|
||||||
return
|
return
|
||||||
# jitter and delay use the same delay statement
|
|
||||||
if delay is not None:
|
|
||||||
netem += f" delay {delay}us"
|
|
||||||
if jitter is not None:
|
|
||||||
if delay is None:
|
|
||||||
netem += f" delay 0us {jitter}us 25%"
|
|
||||||
else:
|
|
||||||
netem += f" {jitter}us 25%"
|
|
||||||
|
|
||||||
if loss is not None and loss > 0:
|
# delete tc configuration or create and add it
|
||||||
netem += f" loss {min(loss, 100)}%"
|
devname = iface.localname
|
||||||
if duplicate is not None and duplicate > 0:
|
if all(
|
||||||
netem += f" duplicate {min(duplicate, 100)}%"
|
[
|
||||||
|
options.delay is None or options.delay <= 0,
|
||||||
delay_check = delay is None or delay <= 0
|
options.jitter is None or options.jitter <= 0,
|
||||||
jitter_check = jitter is None or jitter <= 0
|
options.loss is None or options.loss <= 0,
|
||||||
loss_check = loss is None or loss <= 0
|
options.dup is None or options.dup <= 0,
|
||||||
duplicate_check = duplicate is None or duplicate <= 0
|
options.bandwidth is None or options.bandwidth <= 0,
|
||||||
if all([delay_check, jitter_check, loss_check, duplicate_check]):
|
]
|
||||||
# possibly remove netem if it exists and parent queue wasn't removed
|
):
|
||||||
if not iface.getparam("has_netem"):
|
if not iface.getparam("has_netem"):
|
||||||
return
|
return
|
||||||
if self.up:
|
if self.up:
|
||||||
cmd = f"{TC} qdisc delete dev {devname} {parent} handle 10:"
|
cmd = f"{TC} qdisc delete dev {devname} root handle 10:"
|
||||||
iface.host_cmd(cmd)
|
iface.host_cmd(cmd)
|
||||||
iface.setparam("has_netem", False)
|
iface.setparam("has_netem", False)
|
||||||
elif len(netem) > 1:
|
else:
|
||||||
|
netem = ""
|
||||||
|
if options.bandwidth is not None:
|
||||||
|
limit = 1000
|
||||||
|
bw = options.bandwidth / 1000
|
||||||
|
if options.delay and options.bandwidth:
|
||||||
|
delay = options.delay / 1000
|
||||||
|
limit = max(2, math.ceil((2 * bw * delay) / (8 * iface.mtu)))
|
||||||
|
netem += f" rate {bw}kbit"
|
||||||
|
netem += f" limit {limit}"
|
||||||
|
if options.delay is not None:
|
||||||
|
netem += f" delay {options.delay}us"
|
||||||
|
if options.jitter is not None:
|
||||||
|
if options.delay is None:
|
||||||
|
netem += f" delay 0us {options.jitter}us 25%"
|
||||||
|
else:
|
||||||
|
netem += f" {options.jitter}us 25%"
|
||||||
|
if options.loss is not None and options.loss > 0:
|
||||||
|
netem += f" loss {min(options.loss, 100)}%"
|
||||||
|
if options.dup is not None and options.dup > 0:
|
||||||
|
netem += f" duplicate {min(options.dup, 100)}%"
|
||||||
if self.up:
|
if self.up:
|
||||||
cmd = f"{TC} qdisc replace dev {devname} {parent} handle 10: {netem}"
|
cmd = f"{TC} qdisc replace dev {devname} root handle 10: netem {netem}"
|
||||||
iface.host_cmd(cmd)
|
iface.host_cmd(cmd)
|
||||||
iface.setparam("has_netem", True)
|
iface.setparam("has_netem", True)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from core.emulator.enumerations import NodeTypes, TransportType
|
||||||
from core.errors import CoreCommandError, CoreError
|
from core.errors import CoreCommandError, CoreError
|
||||||
from core.executables import MOUNT, TEST, UMOUNT
|
from core.executables import MOUNT, TEST, UMOUNT
|
||||||
from core.nodes.base import CoreNetworkBase, CoreNodeBase
|
from core.nodes.base import CoreNetworkBase, CoreNodeBase
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.network import CoreNetwork, GreTap
|
from core.nodes.network import CoreNetwork, GreTap
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -252,7 +252,7 @@ class Rj45Node(CoreNodeBase):
|
||||||
session: "Session",
|
session: "Session",
|
||||||
_id: int = None,
|
_id: int = None,
|
||||||
name: str = None,
|
name: str = None,
|
||||||
mtu: int = 1500,
|
mtu: int = DEFAULT_MTU,
|
||||||
server: DistributedServer = None,
|
server: DistributedServer = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -8,7 +8,7 @@ import netaddr
|
||||||
|
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.nodes.base import CoreNode
|
from core.nodes.base import CoreNode
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.network import PtpNet, WlanNode
|
from core.nodes.network import PtpNet, WlanNode
|
||||||
from core.nodes.physical import Rj45Node
|
from core.nodes.physical import Rj45Node
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
@ -384,7 +384,7 @@ class FRROspfv2(FrrService):
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
if iface.mtu != 1500:
|
if iface.mtu != DEFAULT_MTU:
|
||||||
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
||||||
# the other nodes/nets
|
# the other nodes/nets
|
||||||
return " ip ospf mtu-ignore\n"
|
return " ip ospf mtu-ignore\n"
|
||||||
|
|
|
@ -8,7 +8,7 @@ import netaddr
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.emulator.enumerations import LinkTypes
|
from core.emulator.enumerations import LinkTypes
|
||||||
from core.nodes.base import CoreNode
|
from core.nodes.base import CoreNode
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import DEFAULT_MTU, CoreInterface
|
||||||
from core.nodes.network import PtpNet, WlanNode
|
from core.nodes.network import PtpNet, WlanNode
|
||||||
from core.nodes.physical import Rj45Node
|
from core.nodes.physical import Rj45Node
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
@ -301,7 +301,7 @@ class Ospfv2(QuaggaService):
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
if iface.mtu != 1500:
|
if iface.mtu != DEFAULT_MTU:
|
||||||
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
||||||
# the other nodes/nets
|
# the other nodes/nets
|
||||||
return " ip ospf mtu-ignore\n"
|
return " ip ospf mtu-ignore\n"
|
||||||
|
|
Loading…
Add table
Reference in a new issue