daemon: updates to support configuring and tracking mtu, along with over refactoring

This commit is contained in:
Blake Harnden 2022-01-07 16:03:45 -08:00
parent 0b531d7fd8
commit 871b1ae2af
7 changed files with 93 additions and 151 deletions

View file

@ -196,10 +196,10 @@ class DistributedController:
continue
for name in self.servers:
server = self.servers[name]
self.create_gre_tunnel(node, server, mtu)
self.create_gre_tunnel(node, server, mtu, True)
def create_gre_tunnel(
self, node: CoreNetwork, server: DistributedServer, mtu: int
self, node: CoreNetwork, server: DistributedServer, mtu: int, start: bool
) -> Tuple[GreTap, GreTap]:
"""
Create gre tunnel using a pair of gre taps between the local and remote server.
@ -207,6 +207,7 @@ class DistributedController:
:param node: node to create gre tunnel for
:param server: server to create tunnel for
:param mtu: mtu for gre taps
:param start: True to start gre taps, False otherwise
:return: local and remote gre taps created for tunnel
"""
host = server.host
@ -216,16 +217,18 @@ 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, mtu=mtu)
local_tap.net_client.set_iface_master(node.brname, local_tap.localname)
local_tap = GreTap(self.session, host, key=key, mtu=mtu)
if start:
local_tap.startup()
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, mtu=mtu
)
remote_tap.net_client.set_iface_master(node.brname, remote_tap.localname)
remote_tap = GreTap(self.session, self.address, key=key, server=server, mtu=mtu)
if start:
remote_tap.startup()
remote_tap.net_client.set_iface_master(node.brname, remote_tap.localname)
# save tunnels for shutdown
tunnel = (local_tap, remote_tap)
self.tunnels[key] = tunnel

View file

@ -1496,6 +1496,7 @@ class Session:
mac=utils.random_mac(),
ip4=ip4,
ip4_mask=ip4_mask,
mtu=DEFAULT_MTU,
)
iface = node.new_iface(control_net, iface_data)
iface.control = True

View file

@ -712,9 +712,7 @@ class CoreNode(CoreNodeBase):
with self.lock:
return super().next_iface_id()
def newveth(
self, iface_id: int = None, ifname: str = None, mtu: int = DEFAULT_MTU
) -> int:
def newveth(self, iface_id: int = None, ifname: str = None, mtu: int = None) -> int:
"""
Create a new interface.
@ -724,6 +722,7 @@ class CoreNode(CoreNodeBase):
:return: nothing
"""
with self.lock:
mtu = mtu if mtu is not None else DEFAULT_MTU
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()
@ -732,32 +731,9 @@ class CoreNode(CoreNodeBase):
except TypeError:
suffix = f"{self.id}.{iface_id}.{sessionid}"
localname = f"veth{suffix}"
if len(localname) >= 16:
raise CoreError(f"interface local name ({localname}) too long")
name = f"{localname}p"
if len(name) >= 16:
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)
logger.debug("interface flow index: %s - %s", veth.name, veth.flow_id)
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 CoreError as e:
veth.shutdown()
del veth
raise e
veth = Veth(self.session, name, localname, mtu, self.server, self)
veth.adopt_node(iface_id, ifname, self.up)
return iface_id
def newtuntap(self, iface_id: int = None, ifname: str = None) -> int:
@ -774,12 +750,13 @@ class CoreNode(CoreNodeBase):
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)
tuntap = TunTap(self.session, name, localname, node=self)
if self.up:
tuntap.startup()
try:
self.add_iface(tuntap, iface_id)
except CoreError as e:
tuntap.shutdown()
del tuntap
raise e
return iface_id

View file

@ -33,25 +33,28 @@ class CoreInterface:
def __init__(
self,
session: "Session",
node: "CoreNode",
name: str,
localname: str,
mtu: int,
mtu: int = DEFAULT_MTU,
server: "DistributedServer" = None,
node: "CoreNode" = None,
) -> None:
"""
Creates a CoreInterface instance.
:param session: core session instance
:param node: node for interface
:param name: interface name
:param localname: interface local name
:param mtu: mtu value
:param server: remote server node
will run on, default is None for localhost
:param server: remote server node will run on, default is None for localhost
:param node: node for interface
"""
if len(name) >= 16:
raise CoreError(f"interface name ({name}) too long, max 16")
if len(localname) >= 16:
raise CoreError(f"interface local name ({localname}) too long, max 16")
self.session: "Session" = session
self.node: "CoreNode" = node
self.node: Optional["CoreNode"] = node
self.name: str = name
self.localname: str = localname
self.up: bool = False
@ -128,7 +131,6 @@ class CoreInterface:
if self.net:
self.detachnet()
self.net = None
net.attach(self)
self.net = net
@ -279,11 +281,9 @@ class CoreInterface:
logger.debug("setting param: %s - %s", key, value)
if value is None or value < 0:
return False
current_value = self._params.get(key)
if current_value is not None and current_value == value:
return False
self._params[key] = value
return True
@ -342,33 +342,32 @@ class Veth(CoreInterface):
Provides virtual ethernet functionality for core nodes.
"""
def __init__(
self,
session: "Session",
node: "CoreNode",
name: str,
localname: str,
mtu: int = DEFAULT_MTU,
server: "DistributedServer" = None,
start: bool = True,
) -> None:
def adopt_node(self, iface_id: int, name: str, start: bool) -> None:
"""
Creates a VEth instance.
Adopt this interface to the provided node, configuring and associating
with the node as needed.
:param session: core session instance
:param node: related core node
:param name: interface name
:param localname: interface local name
:param mtu: interface mtu
:param server: remote server node
will run on, default is None for localhost
:param start: start flag
:raises CoreCommandError: when there is a command exception
:param iface_id: interface id for node
:param name: name of interface fo rnode
:param start: True to start interface, False otherwise
:return: nothing
"""
# note that net arg is ignored
super().__init__(session, node, name, localname, mtu, server)
if start:
self.startup()
self.net_client.device_ns(self.name, str(self.node.pid))
self.node.node_net_client.checksums_off(self.name)
self.flow_id = self.node.node_net_client.get_ifindex(self.name)
logger.debug("interface flow index: %s - %s", self.name, self.flow_id)
mac = self.node.node_net_client.get_mac(self.name)
logger.debug("interface mac: %s - %s", self.name, mac)
self.set_mac(mac)
self.node.node_net_client.device_name(self.name, name)
self.name = name
try:
self.node.add_iface(self, iface_id)
except CoreError as e:
self.shutdown()
raise e
def startup(self) -> None:
"""
@ -410,32 +409,6 @@ class TunTap(CoreInterface):
TUN/TAP virtual device in TAP mode
"""
def __init__(
self,
session: "Session",
node: "CoreNode",
name: str,
localname: str,
mtu: int = DEFAULT_MTU,
server: "DistributedServer" = None,
start: bool = True,
) -> None:
"""
Create a TunTap instance.
:param session: core session instance
:param node: related core node
:param name: interface name
:param localname: local interface name
:param mtu: interface mtu
:param server: remote server node
will run on, default is None for localhost
:param start: start flag
"""
super().__init__(session, node, name, localname, mtu, server)
if start:
self.startup()
def startup(self) -> None:
"""
Startup logic for a tunnel tap.
@ -582,47 +555,53 @@ class GreTap(CoreInterface):
def __init__(
self,
session: "Session",
remoteip: str,
key: int = None,
node: "CoreNode" = None,
name: str = None,
session: "Session" = None,
mtu: int = DEFAULT_MTU,
remoteip: str = None,
_id: int = None,
localip: str = None,
ttl: int = 255,
key: int = None,
start: bool = True,
server: "DistributedServer" = None,
) -> None:
"""
Creates a GreTap instance.
:param node: related core node
:param name: interface name
:param session: core session instance
:param mtu: interface mtu
:param remoteip: remote address
:param key: gre tap key
:param node: related core node
:param mtu: interface mtu
:param _id: object id
:param localip: local address
:param ttl: ttl value
:param key: gre tap key
:param start: start flag
:param server: remote server node
will run on, default is None for localhost
:raises CoreCommandError: when there is a command exception
"""
if _id is None:
_id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF
self.id = _id
self.id: int = _id
sessionid = session.short_session_id()
localname = f"gt.{self.id}.{sessionid}"
super().__init__(session, node, name, localname, mtu, server)
self.transport_type = TransportType.RAW
if not start:
return
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)
name = f"{localname}p"
super().__init__(session, name, localname, mtu, server, node)
self.transport_type: TransportType = TransportType.RAW
self.remote_ip: str = remoteip
self.ttl: int = ttl
self.key: Optional[int] = key
self.local_ip: Optional[str] = localip
def startup(self) -> None:
"""
Startup logic for a GreTap.
:return: nothing
"""
self.net_client.create_gretap(
self.localname, self.remote_ip, self.local_ip, self.ttl, self.key
)
if self.mtu > 0:
self.net_client.set_mtu(self.localname, self.mtu)
self.net_client.device_up(self.localname)

View file

@ -95,14 +95,14 @@ class LinuxNetClient:
"""
return self.run(f"cat /sys/class/net/{device}/address")
def get_ifindex(self, device: str) -> str:
def get_ifindex(self, device: str) -> int:
"""
Retrieve ifindex for a given device.
:param device: device to get ifindex for
:return: ifindex
"""
return self.run(f"cat /sys/class/net/{device}/ifindex")
return int(self.run(f"cat /sys/class/net/{device}/ifindex"))
def device_ns(self, device: str, namespace: str) -> None:
"""

View file

@ -484,21 +484,15 @@ class CoreNetwork(CoreNetworkBase):
_id = f"{self.id:x}"
except TypeError:
_id = str(self.id)
try:
net_id = f"{net.id:x}"
except TypeError:
net_id = str(net.id)
localname = f"veth{_id}.{net_id}.{sessionid}"
if len(localname) >= 16:
raise ValueError(f"interface local name {localname} too long")
name = f"veth{net_id}.{_id}.{sessionid}"
if len(name) >= 16:
raise ValueError(f"interface name {name} too long")
iface = Veth(self.session, None, name, localname, start=self.up)
iface = Veth(self.session, name, localname)
if self.up:
iface.startup()
self.attach(iface)
if net.up and net.brname:
iface.net_client.set_iface_master(net.brname, iface.name)
@ -578,14 +572,14 @@ class GreTapBridge(CoreNetwork):
self.localip: Optional[str] = localip
self.ttl: int = ttl
self.gretap: Optional[GreTap] = None
if remoteip is not None:
if self.remoteip is not None:
self.gretap = GreTap(
session,
remoteip,
key=self.grekey,
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
mtu=self.mtu,
)
@ -597,6 +591,7 @@ class GreTapBridge(CoreNetwork):
"""
super().startup()
if self.gretap:
self.gretap.startup()
self.attach(self.gretap)
def shutdown(self) -> None:
@ -628,13 +623,14 @@ class GreTapBridge(CoreNetwork):
if len(ips) > 1:
localip = ips[1].split("/")[0]
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
self.session,
remoteip,
key=self.grekey,
localip=localip,
ttl=self.ttl,
key=self.grekey,
mtu=self.mtu,
)
self.startup()
self.attach(self.gretap)
def setkey(self, key: int, iface_data: InterfaceData) -> None:

View file

@ -14,7 +14,7 @@ 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 DEFAULT_MTU, CoreInterface
from core.nodes.network import CoreNetwork, GreTap
from core.nodes.network import CoreNetwork
logger = logging.getLogger(__name__)
@ -173,25 +173,11 @@ class PhysicalNode(CoreNodeBase):
name = iface_data.name
if name is None:
name = f"gt{iface_id}"
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, 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,
mtu=iface_data.mtu,
)
self.adopt_iface(iface, iface_id, iface_data.mac, ips)
return iface
_, remote_tap = self.session.distributed.create_gre_tunnel(
net, self.server, iface_data.mtu, self.up
)
self.adopt_iface(remote_tap, iface_id, iface_data.mac, ips)
return remote_tap
def privatedir(self, dir_path: Path) -> None:
if not str(dir_path).startswith("/"):