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.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…
	
	Add table
		Add a link
		
	
		Reference in a new issue