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