Skip to content

Commit 8907560

Browse files
authored
feat(net): render vlan, bond, bridge for v1 network state (#6538)
Including network_data.json Fixes GH-6534 Signed-off-by: Mathieu Parent <math.parent@gmail.com>
1 parent 009c0ec commit 8907560

38 files changed

Lines changed: 308 additions & 91 deletions

cloudinit/net/networkd.py

Lines changed: 86 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -388,27 +388,21 @@ def extractRoutingPolicies(self, nsCfg: Dict):
388388

389389
def _render_content(self, ns: NetworkState):
390390
ret_dict = {}
391-
vlan_link = {}
392-
bond_link = {}
393-
bridge_link = {}
394-
395-
if "vlans" in ns.config:
396-
vlan_dict = self.render_vlans(ns)
397-
vlan_netdev = vlan_dict["vlan_netdev"]
398-
vlan_link = vlan_dict["vlan_link"]
399-
ret_dict["vlan_netdev"] = vlan_netdev
400-
401-
if "bonds" in ns.config:
402-
bond_dict = self.render_bonds(ns)
403-
bond_netdev = bond_dict["bond_netdev"]
404-
bond_link = bond_dict["bond_link"]
405-
ret_dict["bond_netdev"] = bond_netdev
406-
407-
if "bridges" in ns.config:
408-
bridge_dict = self.render_bridges(ns)
409-
bridge_netdev = bridge_dict["bridge_netdev"]
410-
bridge_link = bridge_dict["bridge_link"]
411-
ret_dict["bridge_netdev"] = bridge_netdev
391+
392+
vlan_dict = self.render_vlans(ns)
393+
vlan_netdev = vlan_dict["vlan_netdev"]
394+
vlan_link = vlan_dict["vlan_link"]
395+
ret_dict["vlan_netdev"] = vlan_netdev
396+
397+
bond_dict = self.render_bonds(ns)
398+
bond_netdev = bond_dict["bond_netdev"]
399+
bond_link = bond_dict["bond_link"]
400+
ret_dict["bond_netdev"] = bond_netdev
401+
402+
bridge_dict = self.render_bridges(ns)
403+
bridge_netdev = bridge_dict["bridge_netdev"]
404+
bridge_link = bridge_dict["bridge_link"]
405+
ret_dict["bridge_netdev"] = bridge_netdev
412406

413407
routingPolicies = self.extractRoutingPolicies(ns.config)
414408

@@ -507,34 +501,35 @@ def render_vlans(self, ns: NetworkState) -> dict:
507501
vlan_link_info = defaultdict(list)
508502
vlan_ndev_configs = {}
509503

510-
vlans = ns.config.get("vlans", {})
511-
for vlan_name, vlan_cfg in vlans.items():
512-
vlan_id = vlan_cfg.get("id")
513-
parent = vlan_cfg.get("link")
504+
vlan_filter = renderer.filter_by_type("vlan")
505+
for iface in ns.iter_interfaces(vlan_filter):
506+
iface_name = iface["name"]
507+
vlan_id = iface.get("vlan_id")
508+
parent = iface.get("vlan-raw-device")
514509

515510
if vlan_id is None or parent is None:
516511
LOG.warning(
517-
"Skipping VLAN %s - missing 'id' or 'link'", vlan_name
512+
"Skipping VLAN %s - missing 'id' or 'link'", iface_name
518513
)
519514
continue
520515

521-
vlan_link_info[parent].append(vlan_name)
516+
vlan_link_info[parent].append(iface_name)
522517

523518
# -------- .netdev for VLAN --------
524519
cfg = CfgParser()
525-
cfg.update_section("NetDev", "Name", vlan_name)
520+
cfg.update_section("NetDev", "Name", iface_name)
526521
cfg.update_section("NetDev", "Kind", "vlan")
527522

528-
val = vlan_cfg.get("mtu")
523+
val = iface.get("mtu")
529524
if val:
530525
cfg.update_section("NetDev", "MTUBytes", val)
531526

532-
val = vlan_cfg.get("macaddress")
527+
val = iface.get("mac_address")
533528
if val:
534529
cfg.update_section("NetDev", "MACAddress", val.lower())
535530

536531
cfg.update_section("VLAN", "Id", vlan_id)
537-
vlan_ndev_configs[vlan_name] = cfg.get_final_conf()
532+
vlan_ndev_configs[iface_name] = cfg.get_final_conf()
538533

539534
return {
540535
"vlan_netdev": vlan_ndev_configs,
@@ -546,69 +541,73 @@ def render_bonds(self, ns: NetworkState) -> dict:
546541
bond_ndev_configs = {}
547542
section = "Bond"
548543

549-
bonds = ns.config.get("bonds", {})
550-
for bond_name, bond_cfg in bonds.items():
551-
interfaces = bond_cfg.get("interfaces")
552-
if not interfaces:
544+
bond_filter = renderer.filter_by_type("bond")
545+
slave_filter = renderer.filter_by_attr("bond-master")
546+
for iface in ns.iter_interfaces(bond_filter):
547+
iface_name = iface["name"]
548+
bond_slaves = [
549+
slave_iface["name"]
550+
for slave_iface in ns.iter_interfaces(slave_filter)
551+
if slave_iface["bond-master"] == iface_name
552+
]
553+
if not bond_slaves:
553554
LOG.warning(
554-
"Skipping bond %s - missing 'interfaces'", bond_name
555+
"Skipping bond %s - missing 'interfaces'", iface_name
555556
)
556557
continue
557558

558-
bond_link_info.update({iface: bond_name for iface in interfaces})
559+
bond_link_info.update({iface: iface_name for iface in bond_slaves})
559560

560561
# -------- .netdev for Bond --------
561562
cfg = CfgParser()
562-
cfg.update_section("NetDev", "Name", bond_name)
563+
cfg.update_section("NetDev", "Name", iface_name)
563564
cfg.update_section("NetDev", "Kind", "bond")
564565

565-
val = bond_cfg.get("mtu")
566+
val = iface.get("mtu")
566567
if val:
567568
cfg.update_section("NetDev", "MTUBytes", val)
568569

569-
val = bond_cfg.get("macaddress")
570+
val = iface.get("mac_address")
570571
if val:
571572
cfg.update_section("NetDev", "MACAddress", val.lower())
572573

573574
# Optional bond parameters
574-
params = bond_cfg.get("parameters", {})
575-
576575
ParamMapType = Dict[str, Tuple[str, Callable[[object], str]]]
577576

578577
param_map: ParamMapType = {
579-
"ad-select": ("AdSelect", str),
580-
"all-slaves-active": (
578+
"bond-ad-select": ("AdSelect", str),
579+
"bond-arp-interval": ("ARPIntervalSec", lambda v: f"{v}ms"),
580+
"bond-arp-validate": ("ARPValidate", str),
581+
"bond-downdelay": ("DownDelaySec", lambda v: f"{v}ms"),
582+
"bond-fail-over-mac": ("FailOverMACPolicy", str),
583+
"bond-lacp-rate": ("LACPTransmitRate", str),
584+
"bond-miimon": ("MIIMonitorSec", lambda v: f"{v}ms"),
585+
"bond-min-links": ("MinLinks", str),
586+
"bond-mode": ("Mode", str),
587+
"bond-num-grat-arp": ("GratuitousARP", str),
588+
"bond-primary-reselect": ("PrimaryReselectPolicy", str),
589+
"bond-updelay": ("UpDelaySec", lambda v: f"{v}ms"),
590+
"bond-xmit-hash-policy": ("TransmitHashPolicy", str),
591+
"bond-all-slaves-active": (
581592
"AllSlavesActive",
582593
lambda v: str(v).lower(),
583594
),
584-
"arp-all-targets": ("ARPAllTargets", str),
585-
"arp-interval": ("ARPIntervalSec", lambda v: f"{v}ms"),
586-
"arp-validate": ("ARPValidate", str),
587-
"down-delay": ("DownDelaySec", lambda v: f"{v}ms"),
588-
"fail-over-mac-policy": ("FailOverMACPolicy", str),
589-
"gratuitous-arp": ("GratuitousARP", str),
590-
"lacp-rate": ("LACPTransmitRate", str),
591-
"learn-packet-interval": ("LearnPacketIntervalSec", str),
592-
"mii-monitor-interval": ("MIIMonitorSec", lambda v: f"{v}ms"),
593-
"min-links": ("MinLinks", str),
594-
"mode": ("Mode", str),
595-
"packets-per-slave": ("PacketsPerSlave", str),
596-
"primary-reselect-policy": ("PrimaryReselectPolicy", str),
597-
"transmit-hash-policy": ("TransmitHashPolicy", str),
598-
"up-delay": ("UpDelaySec", lambda v: f"{v}ms"),
595+
"bond-arp-all-targets": ("ARPAllTargets", str),
596+
"bond-learn-packet-interval": ("LearnPacketIntervalSec", str),
597+
"bond-packets-per-slave": ("PacketsPerSlave", str),
599598
}
600599

601600
for key, (option, formatter) in param_map.items():
602-
if key in params:
603-
cfg.update_section(section, option, formatter(params[key]))
601+
if key in iface:
602+
cfg.update_section(section, option, formatter(iface[key]))
604603

605-
if "arp-ip-targets" in params:
606-
targets = params["arp-ip-targets"]
604+
if "arp-ip-targets" in iface:
605+
targets = iface["arp-ip-targets"]
607606
if isinstance(targets, str):
608607
targets = [targets]
609608
cfg.update_section(section, "ARPIPTargets", " ".join(targets))
610609

611-
bond_ndev_configs[bond_name] = cfg.get_final_conf()
610+
bond_ndev_configs[iface_name] = cfg.get_final_conf()
612611

613612
return {
614613
"bond_netdev": bond_ndev_configs,
@@ -624,58 +623,58 @@ def render_bridges(self, ns: NetworkState) -> dict:
624623

625624
bridge_ndev_configs = {}
626625

627-
bridges = ns.config.get("bridges", {})
628-
for bridge_name, bridge_cfg in bridges.items():
629-
interfaces = bridge_cfg.get("interfaces", [])
630-
if not interfaces:
626+
bridge_filter = renderer.filter_by_type("bridge")
627+
for iface in ns.iter_interfaces(bridge_filter):
628+
iface_name = iface["name"]
629+
bridge_ports = iface.get("bridge_ports", [])
630+
if not bridge_ports:
631631
LOG.warning(
632-
"Skipping bridge %s - missing 'interfaces'", bridge_name
632+
"Skipping bridge %s - missing 'interfaces'", iface_name
633633
)
634634
continue
635635

636636
# Map each interface to its bridge
637-
for iface in interfaces:
638-
bridge_link_info[iface] = bridge_name
637+
for bridge_port in bridge_ports:
638+
bridge_link_info[bridge_port] = iface_name
639639

640640
# ---- .netdev config for the bridge ----
641641
cfg = CfgParser()
642-
cfg.update_section("NetDev", "Name", bridge_name)
642+
cfg.update_section("NetDev", "Name", iface_name)
643643
cfg.update_section("NetDev", "Kind", "bridge")
644644

645-
val = bridge_cfg.get("mtu")
645+
val = iface.get("mtu")
646646
if val:
647647
cfg.update_section("NetDev", "MTUBytes", val)
648648

649-
val = bridge_cfg.get("macaddress")
649+
val = iface.get("mac_address")
650650
if val:
651651
cfg.update_section("NetDev", "MACAddress", val.lower())
652652

653653
# Bridge parameters
654-
params = bridge_cfg.get("parameters", {})
655654
param_map = {
656-
"ageing-time": "AgeingTimeSec",
657-
"forward-delay": "ForwardDelaySec",
658-
"hello-time": "HelloTimeSec",
659-
"max-age": "MaxAgeSec",
660-
"priority": "Priority",
661-
"stp": "STP",
655+
"bridge_ageing": "AgeingTimeSec",
656+
"bridge_bridgeprio": "Priority",
657+
"bridge_fd": "ForwardDelaySec",
658+
"bridge_hello": "HelloTimeSec",
659+
"bridge_maxage": "MaxAgeSec",
660+
"bridge_stp": "STP",
662661
}
663662
for key, sysd_key in param_map.items():
664-
val = params.get(key)
663+
val = iface.get(key)
665664
if val:
666665
if isinstance(val, bool):
667666
val = "yes" if val else "no"
668667
cfg.update_section("Bridge", sysd_key, val)
669668

670-
val = params.get("path-cost")
669+
val = iface.get("bridge_pathcost")
671670
if val:
672-
bridge_link_info["path-cost"][bridge_name] = val
671+
bridge_link_info["path-cost"][iface_name] = val
673672

674-
val = params.get("port-priority")
673+
val = iface.get("bridge_portprio")
675674
if val:
676-
bridge_link_info["port-priority"][bridge_name] = val
675+
bridge_link_info["port-priority"][iface_name] = val
677676

678-
bridge_ndev_configs[bridge_name] = cfg.get_final_conf()
677+
bridge_ndev_configs[iface_name] = cfg.get_final_conf()
679678

680679
return {
681680
"bridge_netdev": bridge_ndev_configs,
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
network:
2+
version: 1
3+
4+
config:
5+
- mac_address: 00:00:00:00:00:01
6+
mtu: 1500
7+
name: slot1port1
8+
subnets: []
9+
type: physical
10+
- mac_address: 00:00:00:00:00:02
11+
mtu: 1500
12+
name: slot1port2
13+
subnets: []
14+
type: physical
15+
- mac_address: 00:00:00:00:01:01
16+
mtu: 1500
17+
name: slot2port1
18+
subnets: []
19+
type: physical
20+
- mac_address: 00:00:00:00:01:02
21+
mtu: 1500
22+
name: slot2port2
23+
subnets: []
24+
type: physical
25+
- mac_address: 00:00:00:00:02:01
26+
mtu: 1500
27+
name: slot3port1
28+
subnets: []
29+
type: physical
30+
- mac_address: 00:00:00:00:02:02
31+
mtu: 1500
32+
name: slot3port2
33+
subnets: []
34+
type: physical
35+
- bond_interfaces:
36+
- slot1port1
37+
- slot3port1
38+
mac_address: 01:00:00:00:00:01
39+
mtu: 1500
40+
name: bond0
41+
params:
42+
bond-mode: active-backup
43+
subnets:
44+
- address: 10.11.12.13
45+
ipv4: true
46+
netmask: 255.255.255.0
47+
type: static
48+
type: bond
49+
- bond_interfaces:
50+
- slot1port2
51+
- slot2port1
52+
mac_address: 01:00:00:00:00:02
53+
mtu: 1500
54+
name: bond1
55+
params:
56+
bond-mode: active-backup
57+
subnets:
58+
- address: 10.20.30.2
59+
ipv4: true
60+
netmask: 255.255.255.0
61+
routes:
62+
- gateway: 10.20.30.1
63+
netmask: 0.0.0.0
64+
network: 0.0.0.0
65+
type: static
66+
type: bond
67+
- bond_interfaces:
68+
- slot2port2
69+
- slot3port2
70+
mac_address: 01:00:00:00:00:02
71+
mtu: 1500
72+
name: bond2
73+
params:
74+
bond-mode: active-backup
75+
subnets:
76+
- address: 10.20.30.3
77+
ipv4: true
78+
netmask: 255.255.255.0
79+
type: static
80+
type: bond
81+
- address: 8.8.8.8
82+
type: nameserver
83+
- address: 4.4.4.4
84+
type: nameserver
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Bond]
2+
Mode=active-backup
3+
4+
[NetDev]
5+
Kind=bond
6+
MACAddress=01:00:00:00:00:01
7+
MTUBytes=1500
8+
Name=bond0
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Address]
2+
Address=10.11.12.13/24
3+
4+
[Link]
5+
MACAddress=01:00:00:00:00:01
6+
MTUBytes=1500
7+
8+
[Match]
9+
Name=bond0
10+
11+
[Network]
12+
DHCP=no
13+
DNS=8.8.8.8 4.4.4.4
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Bond]
2+
Mode=active-backup
3+
4+
[NetDev]
5+
Kind=bond
6+
MACAddress=01:00:00:00:00:02
7+
MTUBytes=1500
8+
Name=bond1

0 commit comments

Comments
 (0)