Skip to content

Commit

Permalink
munet: add better hostintf support
Browse files Browse the repository at this point in the history
  • Loading branch information
choppsv1 committed May 1, 2024
1 parent 65fd021 commit e577d39
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 15 deletions.
8 changes: 8 additions & 0 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,14 @@ munet>
"IPv6 prefix for the network. If host bit's are set then the linux
bridge will be assigned that IP.";
}
leaf external {
type boolean;
default false;
description
"This is a placeholder network for an externally defined network.
This is most useful when adding host interfaces to nodes as the
connection point.";
}
}

list nodes {
Expand Down
3 changes: 3 additions & 0 deletions munet/munet-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@
},
"ipv6": {
"type": "string"
},
"external": {
"type": "boolean"
}
}
}
Expand Down
53 changes: 38 additions & 15 deletions munet/native.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
from .base import BaseMunet
from .base import Bridge
from .base import Commander
from .base import InterfaceMixin
from .base import LinuxNamespace
from .base import MunetError
from .base import SharedNamespace
from .base import Timeout
from .base import _async_get_exec_path
from .base import _get_exec_path
Expand Down Expand Up @@ -132,6 +134,22 @@ def convert_ranges_to_bitmask(ranges):
return bitmask


class ExternalNetwork(SharedNamespace, InterfaceMixin):
"""A network external to munet."""

def __init__(self, name=None, unet=None, logger=None, mtu=None, config=None):
"""Create an external network."""
del logger # avoid linter
del mtu # avoid linter
# Do we want to use os.getpid() rather than unet.pid?
super().__init__(name, pid=unet.pid, nsflags=unet.nsflags, unet=unet)
self.config = config if config else {}

async def _async_delete(self):
self.logger.debug("%s: deleting", self)
await super()._async_delete()


class L2Bridge(Bridge):
"""A linux bridge with no IP network address."""

Expand Down Expand Up @@ -979,17 +997,16 @@ async def add_host_intf(self, hname, lname, mtu=None):
)
self.unet.rootcmd.cmd_status(f"ip link set {dname} name {hname}")

rc, o, _ = self.unet.rootcmd.cmd_status("ip -o link show")
m = re.search(rf"\d+:\s+{re.escape(hname)}:.*", o)
if m:
self.unet.rootcmd.cmd_nostatus(f"ip link set {hname} down ")
self.unet.rootcmd.cmd_raises(f"ip link set {hname} netns {self.pid}")
# Make sure the interface is there.
self.unet.rootcmd.cmd_raises(f"ip -o link show {hname}")
self.unet.rootcmd.cmd_nostatus(f"ip link set {hname} down ")
self.unet.rootcmd.cmd_raises(f"ip link set {hname} netns {self.pid}")

# Wait for interface to show up in namespace
for retry in range(0, 10):
rc, o, _ = self.cmd_status(f"ip -o link show {hname}")
if not rc:
if re.search(rf"\d+: {re.escape(hname)}:.*", o):
break
break
if retry > 0:
await asyncio.sleep(1)
self.cmd_raises(f"ip link set {hname} name {lname}")
Expand All @@ -1001,12 +1018,11 @@ async def rem_host_intf(self, hname):
lname = self.host_intfs[hname]
self.cmd_raises(f"ip link set {lname} down")
self.cmd_raises(f"ip link set {lname} name {hname}")
self.cmd_status(f"ip link set netns 1 dev {hname}")
# The above is failing sometimes and not sure why
# logging.error(
# "XXX after setns %s",
# self.unet.rootcmd.cmd_nostatus(f"ip link show {hname}"),
# )
# We need to NOT run this command in the new pid namespace so that pid 1 is the
# root init process and so the interface gets returned to the root namespace
self.unet.rootcmd.cmd_raises(
f"nsenter -t {self.pid} -n ip link set netns 1 dev {hname}"
)
del self.host_intfs[hname]

async def add_phy_intf(self, devaddr, lname):
Expand Down Expand Up @@ -2878,7 +2894,9 @@ async def add_native_link(self, node1, node2, c1=None, c2=None):
else:
node2.set_lan_addr(node1, c2)

if "physical" not in c1 and not node1.is_vm:
if isinstance(node1, ExternalNetwork):
pass
elif "physical" not in c1 and not node1.is_vm:
node1.set_intf_constraints(if1, **c1)
if "physical" not in c2 and not node2.is_vm:
node2.set_intf_constraints(if2, **c2)
Expand Down Expand Up @@ -2908,7 +2926,12 @@ def add_network(self, name, config=None, **kwargs):
if config is None:
config = {}

cls = L3Bridge if config.get("ip") else L2Bridge
if config.get("external"):
cls = ExternalNetwork
elif config.get("ip"):
cls = L3Bridge
else:
cls = L2Bridge
mtu = kwargs.get("mtu", config.get("mtu"))
return super().add_switch(name, cls=cls, config=config, mtu=mtu, **kwargs)

Expand Down

0 comments on commit e577d39

Please sign in to comment.