Skip to content

Commit ecd31e2

Browse files
committed
munet: autonumber loopbacks
Configure loopback addresses through the `ip` and `ipv6` node config. Loopbacks are automatically configured by `networks-autonumber`. Signed-off-by: Liam Brady <lbrady@labn.net>
1 parent 04ffb73 commit ecd31e2

File tree

6 files changed

+71
-8
lines changed

6 files changed

+71
-8
lines changed

README.org

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ module: labn-munet-config
4646
| +--rw new-window? boolean
4747
| +--rw top-level? boolean
4848
+--rw kinds* [name]
49+
| +--rw ip? string
50+
| +--rw ipv6? string
4951
| +--rw merge* string
5052
| +--rw cap-add* string
5153
| +--rw cap-remove* string
@@ -134,6 +136,8 @@ module: labn-munet-config
134136
| +--rw nodes* [name]
135137
| +--rw id? uint32
136138
| +--rw kind? -> ../../../kinds/name
139+
| +--rw ip? string
140+
| +--rw ipv6? string
137141
| +--rw cap-add* string
138142
| +--rw cap-remove* string
139143
| +--rw cmd? string
@@ -540,6 +544,14 @@ munet>
540544

541545
grouping common-node {
542546
description "Common node properties";
547+
leaf ip {
548+
type string;
549+
description "IPv4 address and mask for the loopback address.";
550+
}
551+
leaf ipv6 {
552+
type string;
553+
description "IPv6 address and mask for the loopback address.";
554+
}
543555
leaf-list cap-add {
544556
type string;
545557
description "Capabilities to add to a container.";
@@ -1153,4 +1165,3 @@ munet>
11531165
[ -d /yang ] || DOCKER="sudo podman run --net=host -v $(pwd):/work docker.io/labn/org-rfc"
11541166
if ! $DOCKER pyang -P build --lax-quote-checks -Werror --lint $module 2>&1; then echo FAIL; fi
11551167
#+end_src
1156-

doc/source/config.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Topology
7777
--------
7878

7979
The topology section defines the networks and nodes that make up the topology
80-
along withe a few global topology options.
80+
along with a few global topology options.
8181

8282
.. pyang labn-munet-config.yang -f tree --tree-path=/topology
8383
@@ -117,6 +117,8 @@ Tree diagram for node config::
117117
| +--rw nodes* [name]
118118
| +--rw id? uint32
119119
| +--rw kind? -> ../../../kinds/name
120+
| +--rw ip? string
121+
| +--rw ipv6? string
120122
| +--rw cap-add* string
121123
| +--rw cap-remove* string
122124
| +--rw cmd? string

munet/munet-schema.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
"type": "string"
7070
}
7171
},
72+
"ip": {
73+
"type": "string"
74+
},
75+
"ipv6": {
76+
"type": "string"
77+
},
7278
"cap-add": {
7379
"type": "array",
7480
"items": {
@@ -425,6 +431,12 @@
425431
"kind": {
426432
"type": "string"
427433
},
434+
"ip": {
435+
"type": "string"
436+
},
437+
"ipv6": {
438+
"type": "string"
439+
},
428440
"cap-add": {
429441
"type": "array",
430442
"items": {

munet/native.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,24 @@ class L3ContainerNotRunningError(MunetError):
5959

6060

6161
def get_loopback_ips(c, nid):
62+
ips = []
6263
if ip := c.get("ip"):
6364
if ip == "auto":
64-
return [ipaddress.ip_interface("10.255.0.0/32") + nid]
65-
if isinstance(ip, str):
66-
return [ipaddress.ip_interface(ip)]
67-
return [ipaddress.ip_interface(x) for x in ip]
68-
return []
65+
assert nid < 0xFFFF # Limited to 10.255.0.0/16 block
66+
ips.append(ipaddress.ip_interface("10.255.0.0/32") + nid)
67+
elif isinstance(ip, str):
68+
ips.append(ipaddress.ip_interface(ip))
69+
else:
70+
ips.extend([ipaddress.ip_interface(x) for x in ip])
71+
if ipv6 := c.get("ipv6"):
72+
if ipv6 == "auto":
73+
assert nid < 0xFFFF # Same limit as ipv4 for simplicity
74+
ips.append(ipaddress.ip_interface(f"fcfe:ffff:{nid:02x}::1/128"))
75+
elif isinstance(ip, str):
76+
ips.append(ipaddress.ip_interface(ipv6))
77+
else:
78+
ips.extend([ipaddress.ip_interface(x) for x in ipv6])
79+
return ips
6980

7081

7182
def make_ip_network(net, inc):
@@ -94,6 +105,7 @@ def get_ip_network(c, brid, ipv6=False):
94105
return ifip
95106
except ValueError:
96107
return ipaddress.ip_network(ip)
108+
assert brid < 0xFDFF # Limited to 10.0.0.0/16 through 10.253.0.0/16 blocks
97109
if ipv6:
98110
return make_ip_interface("fc00::fe/64", brid)
99111
return make_ip_interface("10.0.0.254/24", brid)
@@ -779,12 +791,16 @@ def __init__(self, *args, unet=None, **kwargs):
779791
self.cmd_raises("sysctl -w net.ipv6.conf.all.disable_ipv6=0")
780792
self.cmd_raises("sysctl -w net.ipv6.conf.all.forwarding=1")
781793

782-
assert self.id < 0xFF * (0xFF - 0x7F) # Beyond this, ipv4 address is invalid
794+
assert self.id < 0x7FFF # Limited to 10.254.0.0/16 block
783795
self.next_p2p_network = ipaddress.ip_network(
784796
f"10.254.{self.id & 0xFF}.{(self.id & 0x7F00) >> 7}/31"
785797
)
786798
self.next_p2p_network6 = ipaddress.ip_network(f"fcff:ffff:{self.id:02x}::/127")
787799

800+
if "ip" not in self.config and self.unet.autonumber:
801+
self.config["ip"] = "auto"
802+
if "ipv6" not in self.config and self.unet.autonumber and self.unet.ipv6_enable:
803+
self.config["ipv6"] = "auto"
788804
self.loopback_ip = None
789805
self.loopback_ips = get_loopback_ips(self.config, self.id)
790806
self.loopback_ip = self.loopback_ips[0] if self.loopback_ips else None

tests/basic/munet.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ topology:
4646
which ping
4747
tail -f /dev/null
4848
- name: r3
49+
ip: "172.16.0.3/32"
50+
ipv6: "fe8f:ffff:3::1/128"
4951
connections:
5052
- to: "net1"
5153
- to: "r2"

tests/basic/test_basic_topology.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ async def test_autonumber_ping(unet_perfunc):
4949
o = await r2.async_cmd_raises("ping -w1 -c1 10.254.2.1")
5050
logging.debug("r2 ping r3 p2p (10.254.2.1) output: %s", o)
5151

52+
o = await r2.async_cmd_raises("ping -w1 -c1 10.255.0.2")
53+
logging.debug("r2 ping lo (10.255.0.2) output: %s", o)
54+
5255
if unet.ipv6_enable:
5356
addr = "fc00:0:0:1::2"
5457
o = await r1.async_cmd_nostatus("ip -6 neigh show dev xyz0")
@@ -74,10 +77,27 @@ async def test_autonumber_ping(unet_perfunc):
7477
o = await r2.async_cmd_raises("ping -w1 -c1 fcff:ffff:2::1")
7578
logging.debug("r2 ping r3 p2p (fcff:ffff:2::1) output: %s", o)
7679

80+
o = await r2.async_cmd_raises("ping -w1 -c1 fcfe:ffff:2::1")
81+
logging.debug("r2 ping lo (fcfe:ffff:2::1) output: %s", o)
82+
7783
o = await r1.async_cmd_nostatus("ip -6 neigh show")
7884
logging.info("ip -6 neigh show: %s", o)
7985

8086

87+
@pytest.mark.parametrize(
88+
"unet_perfunc", ["munet"], indirect=["unet_perfunc"]
89+
)
90+
async def test_basic_config(unet_perfunc):
91+
unet = unet_perfunc
92+
r3 = unet.hosts["r3"]
93+
94+
o = await r3.async_cmd_raises("ping -w1 -c1 172.16.0.3")
95+
logging.debug("r1 ping lo (172.16.0.3) output: %s", o)
96+
97+
o = await r3.async_cmd_raises("ping -w1 -c1 fe8f:ffff:3::1")
98+
logging.debug("r1 ping lo (fe8f:ffff:3::1) output: %s", o)
99+
100+
81101
@pytest.mark.parametrize("ipv6", [False, True])
82102
@pytest.mark.parametrize("unet_perfunc", [False, True], indirect=["unet_perfunc"])
83103
async def test_mtu_ping(unet_perfunc, astepf, ipv6):

0 commit comments

Comments
 (0)