daemon: adjustments to support global configurable mtu values for node interfaces and bridges

This commit is contained in:
Blake Harnden 2021-12-21 08:59:48 -08:00
parent 5ff4447528
commit 0b531d7fd8
9 changed files with 72 additions and 50 deletions

View file

@ -142,6 +142,7 @@ class InterfaceData:
ip4_mask: int = None
ip6: str = None
ip6_mask: int = None
mtu: int = None
def get_ips(self) -> List[str]:
"""

View file

@ -187,6 +187,7 @@ class DistributedController:
:return: nothing
"""
mtu = self.session.options.get_config_int("mtu")
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
if not isinstance(node, CoreNetwork):
@ -195,17 +196,17 @@ class DistributedController:
continue
for name in self.servers:
server = self.servers[name]
self.create_gre_tunnel(node, server)
self.create_gre_tunnel(node, server, mtu)
def create_gre_tunnel(
self, node: CoreNetwork, server: DistributedServer
self, node: CoreNetwork, server: DistributedServer, mtu: int
) -> Tuple[GreTap, GreTap]:
"""
Create gre tunnel using a pair of gre taps between the local and remote server.
:param node: node to create gre tunnel for
:param server: server to create
tunnel for
:param server: server to create tunnel for
:param mtu: mtu for gre taps
:return: local and remote gre taps created for tunnel
"""
host = server.host
@ -215,14 +216,14 @@ class DistributedController:
return tunnel
# local to server
logger.info("local tunnel node(%s) to remote(%s) key(%s)", node.name, host, key)
local_tap = GreTap(session=self.session, remoteip=host, key=key)
local_tap = GreTap(session=self.session, remoteip=host, key=key, mtu=mtu)
local_tap.net_client.set_iface_master(node.brname, local_tap.localname)
# server to local
logger.info(
"remote tunnel node(%s) to local(%s) key(%s)", node.name, self.address, key
)
remote_tap = GreTap(
session=self.session, remoteip=self.address, key=key, server=server
session=self.session, remoteip=self.address, key=key, server=server, mtu=mtu
)
remote_tap.net_client.set_iface_master(node.brname, remote_tap.localname)
# save tunnels for shutdown

View file

@ -46,7 +46,7 @@ from core.location.geo import GeoLocation
from core.location.mobility import BasicRangeModel, MobilityManager
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
from core.nodes.docker import DockerNode
from core.nodes.interface import CoreInterface
from core.nodes.interface import DEFAULT_MTU, CoreInterface
from core.nodes.lxd import LxcNode
from core.nodes.network import (
CtrlNet,
@ -253,7 +253,12 @@ class Session:
node2 = self.get_node(node2_id, NodeBase)
iface1 = None
iface2 = None
# set mtu
mtu = self.options.get_config_int("mtu") or DEFAULT_MTU
if iface1_data:
iface1_data.mtu = mtu
if iface2_data:
iface2_data.mtu = mtu
# wireless link
if link_type == LinkTypes.WIRELESS:
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
@ -567,12 +572,18 @@ class Session:
service_class = self.service_manager.get_service(name)
node.add_config_service(service_class)
# set network mtu, if configured
mtu = self.options.get_config_int("mtu")
if isinstance(node, CoreNetworkBase) and mtu > 0:
node.mtu = mtu
# ensure default emane configuration
if isinstance(node, EmaneNet) and options.emane:
model_class = self.emane.get_model(options.emane)
node.model = model_class(self, node.id)
if self.state == EventTypes.RUNTIME_STATE:
self.emane.add_node(node)
# set default wlan config if needed
if isinstance(node, WlanNode):
self.mobility.set_model_config(_id, BasicRangeModel.name)

View file

@ -40,6 +40,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
id="link_interval", default="1", label="EMANE Link Check Interval (sec)"
),
ConfigInt(id="link_timeout", default="4", label="EMANE Link Timeout (sec)"),
ConfigInt(id="mtu", default="0", label="MTU for All Devices"),
]
config_type: RegisterTlvs = RegisterTlvs.UTILITY

View file

@ -18,7 +18,7 @@ from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes
from core.errors import CoreCommandError, CoreError
from core.executables import MOUNT, TEST, VNODED
from core.nodes.client import VnodeClient
from core.nodes.interface import CoreInterface, TunTap, Veth
from core.nodes.interface import DEFAULT_MTU, CoreInterface, TunTap, Veth
from core.nodes.netclient import LinuxNetClient, get_net_client
logger = logging.getLogger(__name__)
@ -712,47 +712,37 @@ class CoreNode(CoreNodeBase):
with self.lock:
return super().next_iface_id()
def newveth(self, iface_id: int = None, ifname: str = None) -> int:
def newveth(
self, iface_id: int = None, ifname: str = None, mtu: int = DEFAULT_MTU
) -> int:
"""
Create a new interface.
:param iface_id: id for the new interface
:param ifname: name for the new interface
:param mtu: mtu for interface
:return: nothing
"""
with self.lock:
if iface_id is None:
iface_id = self.next_iface_id()
if ifname is None:
ifname = f"eth{iface_id}"
iface_id = iface_id if iface_id is not None else self.next_iface_id()
ifname = ifname if ifname is not None else f"eth{iface_id}"
sessionid = self.session.short_session_id()
try:
suffix = f"{self.id:x}.{iface_id}.{sessionid}"
except TypeError:
suffix = f"{self.id}.{iface_id}.{sessionid}"
localname = f"veth{suffix}"
if len(localname) >= 16:
raise ValueError(f"interface local name ({localname}) too long")
name = localname + "p"
raise CoreError(f"interface local name ({localname}) too long")
name = f"{localname}p"
if len(name) >= 16:
raise ValueError(f"interface name ({name}) too long")
veth = Veth(
self.session, self, name, localname, start=self.up, server=self.server
)
raise CoreError(f"interface name ({name}) too long")
veth = Veth(self.session, self, name, localname, mtu, self.server, self.up)
if self.up:
self.net_client.device_ns(veth.name, str(self.pid))
self.node_net_client.device_name(veth.name, ifname)
self.node_net_client.checksums_off(ifname)
veth.name = ifname
if self.up:
flow_id = self.node_net_client.get_ifindex(veth.name)
veth.flow_id = int(flow_id)
@ -760,16 +750,14 @@ class CoreNode(CoreNodeBase):
mac = self.node_net_client.get_mac(veth.name)
logger.debug("interface mac: %s - %s", veth.name, mac)
veth.set_mac(mac)
try:
# add network interface to the node. If unsuccessful, destroy the
# network interface and raise exception.
self.add_iface(veth, iface_id)
except ValueError as e:
except CoreError as e:
veth.shutdown()
del veth
raise e
return iface_id
def newtuntap(self, iface_id: int = None, ifname: str = None) -> int:
@ -781,24 +769,18 @@ class CoreNode(CoreNodeBase):
:return: interface index
"""
with self.lock:
if iface_id is None:
iface_id = self.next_iface_id()
if ifname is None:
ifname = f"eth{iface_id}"
iface_id = iface_id if iface_id is not None else self.next_iface_id()
ifname = ifname if ifname is not None else f"eth{iface_id}"
sessionid = self.session.short_session_id()
localname = f"tap{self.id}.{iface_id}.{sessionid}"
name = ifname
tuntap = TunTap(self.session, self, name, localname, start=self.up)
try:
self.add_iface(tuntap, iface_id)
except ValueError as e:
except CoreError as e:
tuntap.shutdown()
del tuntap
raise e
return iface_id
def set_mac(self, iface_id: int, mac: str) -> None:
@ -879,7 +861,7 @@ class CoreNode(CoreNodeBase):
raise CoreError(
f"node({self.name}) already has interface({iface_id})"
)
iface_id = self.newveth(iface_id, iface_data.name)
iface_id = self.newveth(iface_id, iface_data.name, iface_data.mtu)
self.attachnet(iface_id, net)
if iface_data.mac:
self.set_mac(iface_id, iface_data.mac)
@ -1001,13 +983,14 @@ class CoreNetworkBase(NodeBase):
"""
Create a CoreNetworkBase instance.
:param session: CORE session object
:param session: session object
:param _id: object id
:param name: object name
:param server: remote server node
will run on, default is None for localhost
"""
super().__init__(session, _id, name, server)
self.mtu: int = DEFAULT_MTU
self.brname: Optional[str] = None
self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {}
self.linked_lock: threading.Lock = threading.Lock()

View file

@ -378,6 +378,9 @@ class Veth(CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
self.net_client.create_veth(self.localname, self.name)
if self.mtu > 0:
self.net_client.set_mtu(self.name, self.mtu)
self.net_client.set_mtu(self.localname, self.mtu)
self.net_client.device_up(self.localname)
self.up = True
@ -455,12 +458,10 @@ class TunTap(CoreInterface):
"""
if not self.up:
return
try:
self.node.node_net_client.device_flush(self.name)
except CoreCommandError:
logger.exception("error shutting down tunnel tap")
self.up = False
def waitfor(
@ -584,7 +585,7 @@ class GreTap(CoreInterface):
node: "CoreNode" = None,
name: str = None,
session: "Session" = None,
mtu: int = 1458,
mtu: int = DEFAULT_MTU,
remoteip: str = None,
_id: int = None,
localip: str = None,
@ -622,6 +623,8 @@ class GreTap(CoreInterface):
if remoteip is None:
raise CoreError("missing remote IP required for GRE TAP device")
self.net_client.create_gretap(self.localname, remoteip, localip, ttl, key)
if self.mtu > 0:
self.net_client.set_mtu(self.localname, self.mtu)
self.net_client.device_up(self.localname)
self.up = True

View file

@ -296,6 +296,16 @@ class LinuxNetClient:
"""
self.run(f"{IP} link set {name} type bridge ageing_time {value}")
def set_mtu(self, name: str, value: int) -> None:
"""
Sets the mtu value for a device.
:param name: name of device to set value for
:param value: mtu value to set
:return: nothing
"""
self.run(f"{IP} link set {name} mtu {value}")
class OvsNetClient(LinuxNetClient):
"""

View file

@ -290,12 +290,14 @@ class CoreNetwork(CoreNetworkBase):
def startup(self) -> None:
"""
Linux bridge starup logic.
Linux bridge startup logic.
:return: nothing
:raises CoreCommandError: when there is a command exception
"""
self.net_client.create_bridge(self.brname)
if self.mtu > 0:
self.net_client.set_mtu(self.brname, self.mtu)
self.has_nftables_chain = False
self.up = True
nft_queue.start(self)
@ -584,6 +586,7 @@ class GreTapBridge(CoreNetwork):
localip=localip,
ttl=ttl,
key=self.grekey,
mtu=self.mtu,
)
def startup(self) -> None:
@ -619,7 +622,7 @@ class GreTapBridge(CoreNetwork):
:return: nothing
"""
if self.gretap:
raise ValueError(f"gretap already exists for {self.name}")
raise CoreError(f"gretap already exists for {self.name}")
remoteip = ips[0].split("/")[0]
localip = None
if len(ips) > 1:
@ -630,6 +633,7 @@ class GreTapBridge(CoreNetwork):
localip=localip,
ttl=self.ttl,
key=self.grekey,
mtu=self.mtu,
)
self.attach(self.gretap)

View file

@ -176,12 +176,20 @@ class PhysicalNode(CoreNodeBase):
if self.up:
# this is reached when this node is linked to a network node
# tunnel to net not built yet, so build it now and adopt it
_, remote_tap = self.session.distributed.create_gre_tunnel(net, self.server)
_, remote_tap = self.session.distributed.create_gre_tunnel(
net, self.server, iface_data.mtu
)
self.adopt_iface(remote_tap, iface_id, iface_data.mac, ips)
return remote_tap
else:
# this is reached when configuring services (self.up=False)
iface = GreTap(node=self, name=name, session=self.session, start=False)
iface = GreTap(
node=self,
name=name,
session=self.session,
start=False,
mtu=iface_data.mtu,
)
self.adopt_iface(iface, iface_id, iface_data.mac, ips)
return iface