daemon: updated linkconfig to calculate a limit when bw/delay are present, updated and simplified logic as well, leveraging code from outstanding pull request, updated code to factor in the mtu of the iface being configured
This commit is contained in:
parent
83ba6cea70
commit
380d411833
9 changed files with 65 additions and 78 deletions
|
@ -788,14 +788,18 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
|||
options = LinkOptions()
|
||||
options.delay = message.get_tlv(LinkTlvs.DELAY.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.mer = message.get_tlv(LinkTlvs.MER.value)
|
||||
options.burst = message.get_tlv(LinkTlvs.BURST.value)
|
||||
options.mburst = message.get_tlv(LinkTlvs.MBURST.value)
|
||||
options.unidirectional = message.get_tlv(LinkTlvs.UNIDIRECTIONAL.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:
|
||||
self.session.add_link(
|
||||
|
|
|
@ -5,7 +5,7 @@ from core.config import Configuration
|
|||
from core.configservice.base import ConfigService, ConfigServiceMode
|
||||
from core.emane.nodes import EmaneNet
|
||||
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
|
||||
|
||||
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
|
||||
GreTap device.
|
||||
"""
|
||||
if iface.mtu != 1500:
|
||||
if iface.mtu != DEFAULT_MTU:
|
||||
return True
|
||||
if not iface.net:
|
||||
return False
|
||||
|
|
|
@ -6,7 +6,7 @@ from core.config import Configuration
|
|||
from core.configservice.base import ConfigService, ConfigServiceMode
|
||||
from core.emane.nodes import EmaneNet
|
||||
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
|
||||
|
||||
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
|
||||
GreTap device.
|
||||
"""
|
||||
if iface.mtu != 1500:
|
||||
if iface.mtu != DEFAULT_MTU:
|
||||
return True
|
||||
if not iface.net:
|
||||
return False
|
||||
|
|
|
@ -30,8 +30,6 @@ if TYPE_CHECKING:
|
|||
CoreServices = List[Union[CoreService, Type[CoreService]]]
|
||||
ConfigServiceType = Type[ConfigService]
|
||||
|
||||
_DEFAULT_MTU = 1500
|
||||
|
||||
|
||||
class NodeBase(abc.ABC):
|
||||
"""
|
||||
|
|
|
@ -19,6 +19,8 @@ if TYPE_CHECKING:
|
|||
from core.emulator.session import Session
|
||||
from core.nodes.base import CoreNetworkBase, CoreNode
|
||||
|
||||
DEFAULT_MTU: int = 1500
|
||||
|
||||
|
||||
class CoreInterface:
|
||||
"""
|
||||
|
@ -338,7 +340,7 @@ class Veth(CoreInterface):
|
|||
node: "CoreNode",
|
||||
name: str,
|
||||
localname: str,
|
||||
mtu: int = 1500,
|
||||
mtu: int = DEFAULT_MTU,
|
||||
server: "DistributedServer" = None,
|
||||
start: bool = True,
|
||||
) -> None:
|
||||
|
@ -403,7 +405,7 @@ class TunTap(CoreInterface):
|
|||
node: "CoreNode",
|
||||
name: str,
|
||||
localname: str,
|
||||
mtu: int = 1500,
|
||||
mtu: int = DEFAULT_MTU,
|
||||
server: "DistributedServer" = None,
|
||||
start: bool = True,
|
||||
) -> None:
|
||||
|
|
|
@ -3,6 +3,7 @@ Defines network nodes used within core.
|
|||
"""
|
||||
|
||||
import logging
|
||||
import math
|
||||
import threading
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type
|
||||
|
@ -447,77 +448,59 @@ class CoreNetwork(CoreNetworkBase):
|
|||
:param iface2: interface two
|
||||
:return: nothing
|
||||
"""
|
||||
devname = iface.localname
|
||||
tc = f"{TC} qdisc replace dev {devname}"
|
||||
parent = "root"
|
||||
changed = False
|
||||
bw = options.bandwidth
|
||||
if iface.setparam("bw", bw):
|
||||
# from tc-tbf(8): minimum value for burst is rate / kernel_hz
|
||||
burst = max(2 * iface.mtu, int(bw / 1000))
|
||||
# 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))
|
||||
# determine if any settings have changed
|
||||
changed = any(
|
||||
[
|
||||
iface.setparam("bw", options.bandwidth),
|
||||
iface.setparam("delay", options.delay),
|
||||
iface.setparam("loss", options.loss),
|
||||
iface.setparam("duplicate", options.dup),
|
||||
iface.setparam("jitter", options.jitter),
|
||||
]
|
||||
)
|
||||
if not changed:
|
||||
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:
|
||||
netem += f" loss {min(loss, 100)}%"
|
||||
if duplicate is not None and duplicate > 0:
|
||||
netem += f" duplicate {min(duplicate, 100)}%"
|
||||
|
||||
delay_check = delay is None or delay <= 0
|
||||
jitter_check = jitter is None or jitter <= 0
|
||||
loss_check = loss is None or loss <= 0
|
||||
duplicate_check = duplicate is None or duplicate <= 0
|
||||
if all([delay_check, jitter_check, loss_check, duplicate_check]):
|
||||
# possibly remove netem if it exists and parent queue wasn't removed
|
||||
# delete tc configuration or create and add it
|
||||
devname = iface.localname
|
||||
if all(
|
||||
[
|
||||
options.delay is None or options.delay <= 0,
|
||||
options.jitter is None or options.jitter <= 0,
|
||||
options.loss is None or options.loss <= 0,
|
||||
options.dup is None or options.dup <= 0,
|
||||
options.bandwidth is None or options.bandwidth <= 0,
|
||||
]
|
||||
):
|
||||
if not iface.getparam("has_netem"):
|
||||
return
|
||||
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.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:
|
||||
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.setparam("has_netem", True)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ from core.emulator.enumerations import NodeTypes, TransportType
|
|||
from core.errors import CoreCommandError, CoreError
|
||||
from core.executables import MOUNT, TEST, UMOUNT
|
||||
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
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -252,7 +252,7 @@ class Rj45Node(CoreNodeBase):
|
|||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
mtu: int = 1500,
|
||||
mtu: int = DEFAULT_MTU,
|
||||
server: DistributedServer = None,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
|
@ -8,7 +8,7 @@ import netaddr
|
|||
|
||||
from core.emane.nodes import EmaneNet
|
||||
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.physical import Rj45Node
|
||||
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
|
||||
GreTap device.
|
||||
"""
|
||||
if iface.mtu != 1500:
|
||||
if iface.mtu != DEFAULT_MTU:
|
||||
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
||||
# the other nodes/nets
|
||||
return " ip ospf mtu-ignore\n"
|
||||
|
|
|
@ -8,7 +8,7 @@ import netaddr
|
|||
from core.emane.nodes import EmaneNet
|
||||
from core.emulator.enumerations import LinkTypes
|
||||
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.physical import Rj45Node
|
||||
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
|
||||
GreTap device.
|
||||
"""
|
||||
if iface.mtu != 1500:
|
||||
if iface.mtu != DEFAULT_MTU:
|
||||
# a workaround for PhysicalNode GreTap, which has no knowledge of
|
||||
# the other nodes/nets
|
||||
return " ip ospf mtu-ignore\n"
|
||||
|
|
Loading…
Reference in a new issue